我得到一个奇怪的分段错误。我几乎忽略了它,因为只有当传递给函数的字符串以字母v或更大字母开头时才出现。该程序包含一个由26个链接列表指针组成的数组和一个创建新节点的函数,对它们进行排序(使用另一个函数然后将它们添加到链接列表数组中)。下面是遇到分段错误的代码。
void sort(contact* newContact,int ind, contact** array[]){
contact* current; //pointer to current contact
//Case to test if the contact belongs at the head ###SEGMENTATION FAULT IF name begins with 'v'
if ((*array)[ind] == NULL || strcmp(&(*array)[ind]->name[0],&newContact->name[0])>0){
newContact->next=(*array)[ind]; // contect next pointer is equal to the pointer at index 'ind'
(*array)[ind]=newContact; //goes to array and change the pointer at the index 'ind'
}
else{
current=(*array)[ind]; //updates the current pointer to the first pointer in the index 'ind'
//finds the position to insert contact
while(current->next!=NULL&&strcmp(¤t->next->name[0],&newContact->name[0])<0){
current=current->next; //updates pointer if current is not NULL or current is smaller than new contact
}
//the loop will break at the insertion point.
//inserts contact
newContact->next=current->next;
current->next=newContact;
}
printf("ADDED\n");
}
以下是创建节点的代码,以及在某处出错的情况下收集输入的代码
void addContact(contact* list[]){
contact* new= malloc(sizeof(contact)); // creates new contact and allocates memory for it
printf("NAME: ");
new->name=GetInput(1); //saves the name
printf("NUMBER: ");
new->number=GetInput(0); //saves the number
int x=GetIndex(new->name);
contact** ptr=&list[x];
sort(new,x, &ptr);
printf("Contact Added!\n");
}
对于此函数,如果类型为1,则确保输入的字符串以字母字符开头。如果没有,它就不复存在了
char* GetInput(int type){
int loop=0;
char* buffer; //stores the entire input from the user
if (type==1){
do {
scanf("%ms",&buffer); //takes input from user
//checks if alphabetical
if (isalpha(buffer[0]))
loop=1;
else{
printf("Try again\nThe first character must be alphabetical\n");
free(buffer);
}
}
while(loop==0);
}
//when 1 isnt specified, the input is left untreated
else{
scanf("%ms",&buffer);
}
return buffer;
}
答案 0 :(得分:2)
这段代码有很多问题。您需要做的第一件事就是将编译器上的警告设置调高到最高位置。这里有很多东西不是语法错误,但仍然是一个错误。
一个主要问题(我怀疑运行时错误的来源)位于getInput
:
char* GetInput(int type){
int loop=0;
char* buffer; //stores the entire input from the user
没有。所有buffer
存储都是单个指针值;你实际上并没有放弃任何东西
存储输入。 buffer
并未指出任何有意义的内容。由于它已声明auto
并且您没有明确初始化它,buffer
最初将包含一个随机位模式,可能对应于可写地址,受保护地址或< em>陷阱表示;也就是说,一个位模式不能成为有效的指针值。
尝试写入无效指针值将调用未定义行为,这意味着编译器不需要以任何特定方式处理编码错误。它可以发出诊断和暂停转换,发出诊断并继续转换,或完全忽略该问题。如果它完成转换并生成二进制文件,那么该二进制文件可能会立即崩溃,或者它可能会在错误的状态下跛行,直到其他东西导致它稍后崩溃,或者它可能看起来正常运行。
但是,您已经巧妙地回避了整个问题,如下所示:
if (type==1){
do {
scanf("%ms",&buffer); //takes input from user
^^^^^^^
不是传递buffer
作为你的论点(就像你应该的那样),而是传递&buffer
。与buffer
不同,&buffer
是有效指针(它是buffer
变量的地址),因此您不会尝试通过无效指针写入。很遗憾,&buffer
使用错误的类型 - char **
而不是char *
。您的编译器应已经警告过您;如果它没有,则提高警告级别(同样,m
不是%s
转换说明符AFAIK的有效修饰符;它应该做什么?)。
问题是,buffer
变量仅足以存储单个char *
值(宽度在2到4到8个字节之间,具体取决于平台);因此,如果您的平台上的char *
宽度为4个字节,那么您可以存储最多3个字符的字符串以及终止0字符,并且不会出现任何&#34;坏&#34;会发生(也就是说,你不会覆盖属于不同对象的内存)。任何更长的时间,你都有可能破坏一些重要的事情(可能导致&#34;跛行状态一直处于糟糕的状态,直到其他事情导致事故再次崩溃&#34;结果)。
这里有一种方法,如果不一定是最好的方式,修复该代码(重新格式化以使我的眼睛快速老化更容易;显然,格式化很大程度上取决于品味,所以你可以重新格式化,但你喜欢):
#define FIXED_BUFFER_LEN 20 // Initial buffer size; make this large enough to
// handle most of your expected inputs
char* GetInput( int type )
{
int loop = 1; // yes, I'm changing the sense of this test
/**
* Create a local, temporary buffer for input, large enough to handle
* most expected inputs
*/
char tempBuffer[FIXED_BUFFER_LEN + 1];
/**
* Output buffer pointer, initialized to a known *invalid* value
*/
char* buffer = NULL;
/**
* Build a format string for our scanf statements; a %s without a
* maximum length specifier is a gaping security hole.
*/
char fmt[15]; // stores a string of the form "%DDD...s", where DDD... is
//the field width specifier; for example, "%20s"
/**
* Honestly, you want to check the result of the following operation,
* but I've already spent more time on this than I expected.
*/
sprintf( fmt, "%%%ds", FIXED_BUFFER_LEN );
if (type==1)
{
do
{
scanf( fmt, tempBuffer ); //takes input from user
//checks if alphabetical
if ( isalpha( tempBuffer[0] ))
loop=0;
else
{
printf( "Try again\nThe first character must be alphabetical\n" );
}
}
while( loop );
}
//when 1 isnt specified, the input is left untreated
else
{
scanf( fmt, tempBuffer );
}
/**
* Only now, after we've validated our input, do we allocate the
* dynamic memory for the buffer.
*/
buffer = calloc( strlen( tempBuffer ) + 1, sizeof *buffer );
if ( buffer )
strcpy( buffer, tempBuffer );
return buffer;
}
此代码仍存在一些问题(scanf
许多问题),但这应该会让您朝着正确的方向前进。将编译器上的警告设置尽可能高,然后分析并修复它们中的每一个。