我遇到了一个奇怪的分段错误。我几乎忽略了它,因为它只有在传递给函数的字符串以字母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("ADDEDn");
}
这是创建节点的代码,以及在某个地方出错时收集输入的代码
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 againnThe first character must be alphabeticaln");
free(buffer);
}
}
while(loop==0);
}
//when 1 isnt specified, the input is left untreated
else{
scanf("%ms",&buffer);
}
return buffer;
}
这段代码有很多问题。您需要做的第一件事是将编译器上的警告设置调高到最大程度。这里有很多东西不是语法错误,但仍然是一个错误。
一个主要问题(我怀疑是运行时错误的来源)是getInput
:
char* GetInput(int type){
int loop=0;
char* buffer; //stores the entire input from the user
没有。所有buffer
存储都是单个指针值;你实际上没有留出任何用于输入的存储器。buffer
没有指向任何有意义的地方。由于它被声明为auto
,并且您没有显式初始化它,因此buffer
最初将包含一个随机位模式,该模式可能对应于可写地址、受保护地址或陷阱表示;即不能是有效指针值的位模式。
试图通过无效的指针值进行写入将调用未定义的行为,这只是意味着编译器不需要以任何特定的方式处理编码错误。它可能发出诊断并停止翻译,发出诊断并继续翻译,或者完全忽略问题。如果它完成了翻译并生成了一个二进制文件,那么该二进制文件可能会立即崩溃,或者它可能会在糟糕的状态下蹒跚前行,直到后来发生其他事情导致它崩溃,或者看起来功能正常。
然而,您巧妙地避开了整个问题,如下所示:
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个字符,并且不会发生任何"坏"情况(也就是说,您不会覆盖属于不同对象的内存)。再长一点,你就有可能摔坏一些重要的东西(可能会导致"在糟糕的状态下一瘸一拐,直到后来发生其他事情导致撞车"的结果)。
这里有一种方法,如果不一定是最好的方法,可以修复代码(重新格式化,让我快速衰老的眼睛更容易;显然,格式化在很大程度上是一个品味问题,所以你可以随心所欲地重新格式化):
#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 againnThe first character must be alphabeticaln" );
}
}
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
有许多问题),但这应该会让您朝着正确的方向前进。将编译器上的警告设置尽可能高,并分析和修复其中的每一个。