c-在代码中出现奇怪的分段错误



我遇到了一个奇怪的分段错误。我几乎忽略了它,因为它只有在传递给函数的字符串以字母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(&current->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有许多问题),但这应该会让您朝着正确的方向前进。将编译器上的警告设置尽可能高,并分析和修复其中的每一个。

相关内容

  • 没有找到相关文章

最新更新