【问题标题】:C -Segmentation fault !C-分段错误!
【发布时间】:2010-05-25 16:42:38
【问题描述】:

至少对我来说似乎很奇怪...程序运行正常。但是在我第四次调用 enter() 函数后,出现了分段错误!我将不胜感激。

使用以下函数 enter() 我想将用户命令的数据添加到列表中。

[代码的某些部分已经发布在我的另一个问题上,但我认为我应该再次发布......因为这是我现在面临的另一个问题。]

    /* struct for all the datas that user enters on file*/
typedef struct catalog    
{      char short_name[50];                    
       char surname[50];                       
       signed int amount;                      
       char description[1000];              
       struct catalog *next;
}catalog,*catalogPointer;   

catalogPointer current;
catalogPointer head = NULL; 

void enter(void)    //user command: i <name> <surname> <amount> <description>

{   
    int n,j=2,k=0;
    char temp[1500];
    char *short_name,*surname,*description;
    signed int amount;

    char* params = strchr(command,' ') + 1;  //strchr returns a pointer to the 1st space on the command.U want a pointer to the char right after that space.
    strcpy(temp, params);               //params is saved as temp.

    char *curToken = strtok(temp," ");      //strtok cuts 'temp' into strings between the spaces and saves them to 'curToken'
    printf("temp is:%s \n",temp);

    printf("\nWhat you entered for saving:\n");

    for (n = 0; curToken; ++n)          //until curToken ends:
    {   
        if (curToken)
        {   short_name = malloc(strlen(curToken) + 1);
            strncpy(short_name, curToken, sizeof (short_name));     
        }   
        printf("Short Name: %s \n",short_name);             

        curToken = strtok(NULL," ");                    
        if (curToken)
        {   surname = malloc(strlen(curToken) + 1);
            strncpy(surname, curToken,sizeof (surname));    }   
        printf("SurName: %s \n",surname);

        curToken = strtok(NULL," ");                    
        if (curToken)
        {   //int * amount= malloc(sizeof (signed int *));
            char *chk;                      
            amount = (int) strtol(curToken, &chk, 10);      

            if (!isspace(*chk) && *chk != 0)            
                    fprintf(stderr,"Warning: expected integer value for amount, received %s instead\n",curToken);
        }
        printf("Amount: %d \n",amount);
        curToken = strtok(NULL,"\0");                   
        if (curToken)
        {   description = malloc(strlen(curToken) + 1);
            strncpy(description, curToken, sizeof (description));   
        }
        printf("Description: %s \n",description);
        break;
    }

    if (findEntryExists(head, surname,short_name) != NULL)              //call function in order to see if entry exists already on the catalog
        printf("\nAn entry for <%s %s> is already in the catalog!\nNew entry not entered.\n",short_name,surname);
    else
    {
        printf("\nTry to entry <%s %s %d %s> in the catalog list!\n",short_name,surname,amount,description);
        newEntry(&head,short_name,surname,amount,description);  
        printf("\n**Entry done!**\n");
    }
    // Maintain the list in alphabetical order by surname.


}

catalogPointer findEntryExists (catalogPointer head, char num[],char first[])
{   catalogPointer p = head;
    while (p != NULL && strcmp(p->surname, num) != 0 && strcmp(p->short_name,first) != 0)      
    {   p = p->next;    }
    return p;
}

catalogPointer newEntry (catalog** headRef,char short_name[], char surname[], signed int amount, char description[])
{   
    catalogPointer newNode = (catalogPointer)malloc(sizeof(catalog));
    catalogPointer first;
    catalogPointer second;
    catalogPointer tmp;
    first=head;
    second=NULL;

    strcpy(newNode->short_name, short_name);        
    strcpy(newNode->surname, surname);
    newNode->amount=amount;
    strcpy(newNode->description, description);

    while (first!=NULL)                     
    {       if (strcmp(surname,first->surname)>0)
            second=first;
        else if (strcmp(surname,first->surname)==0)
            {
               if (strcmp(short_name,first->short_name)>0)
                   second=first;
            }
        first=first->next;
    }
    if (second==NULL)
    {       newNode->next=head;
        head=newNode;
    }
    else                             //SEGMENTATION APPEARS WHEN IT GETS HERE!
    {       tmp=second->next;
            newNode->next=tmp;
            first->next=newNode;
    }
}

更新: SegFault 仅在进入 InsertSort() 函数的“else”循环时出现。 我观察到当我尝试将其后的列表名称放入时出现分段错误。 例如,如果在列表中存在:

[姓名:b 姓:b 金额:6 描述:b] [姓名:c 姓:c 金额:5 说明:c] [姓名:d 姓:d 金额:4 描述:d] [姓名:e 姓:e 金额:3 描述:e] [姓名:g 姓:g 数量:2 说明:g] [姓名:x 姓:x 金额:1 描述:x]

我输入:“x z 77 gege”有一个分段 但是如果我输入“x a 77 gege”它会正常继续......

【问题讨论】:

  • 请提供有关崩溃的更多详细信息 - 特别是代码中最有帮助的位置。如果有帮助,也请将此作为参考:stackoverflow.com/questions/2588853/…
  • 命令在哪里定义?而且,您正在泄漏内存而没有释放您 malloc 的东西。
  • 很可能你在某个地方写到数组末尾...
  • @Goz。没错。但是代码有什么问题?我找不到!
  • @FILIaS:是的,因为如果任何条目满足 while 循环中的条件,“first”为 NULL。

标签: c segmentation-fault call


【解决方案1】:

无法发表评论,所以就这样吧:

  while (first!=NULL)  {  //-> this loop can exit ONLY with 'first' being NULL
    if (strcmp(surname,first->surname)>0)
      second=first;
    else if (strcmp(surname,first->surname)==0)  {
      if (strcmp(short_name,first->short_name)>0)
        second=first;
    }
    first=first->next;
  } 
  if (second==NULL) {       
    newNode->next=head;
    head=newNode;
  }
  else { 
    tmp=second->next;
    newNode->next=tmp;
    first->next=newNode; // first used (but it's NULL!)
  }

换句话说,如果你的程序在循环中找到任何满足条件的条目并设置为“秒”,它就会崩溃。 (这会触发列表“内部”的预期添加)。

好的~没有时间等待答案:o),如果你想在“第二个”更改代码之后输入:

  if (second==NULL) {       
    newNode->next=head;
    head=newNode;
  }
  else { 
    newNode->next=second->next;
    second->next=newNode; 
  }

解释(S 是'second',N 是'newNode',A B 只是列表中的一些现有条目):

initial:
       N

  A -> S -> B

first assignment:
       N ---\
            |
            v
  A -> S -> B

second assignment:

       N ---\
       ^    |
       |    v
  A -> S    B

and thus:
  A-> S -> N -> B

【讨论】:

  • 现在的问题是——在这种情况下你想如何插入新条目?在“第二”之后猜测?
【解决方案2】:

不确定是什么导致了这个错误,但我确实看到了这个错误的模式:

char *short_name;
short_name = malloc(strlen(curToken) + 1);
strncpy(short_name, curToken, sizeof (short_name));  

sizeof(short_name) 总是相同的(对于 32 位平台通常为 4,对于 64 位平台通常为 8),因此此处使用的值不正确。你应该这样做:

strncpy(short_name, curToken, strlen(curToken) + 1);

【讨论】:

  • 由于尝试复制以这种方式“初始化”的字符串时会发生段错误,这很可能是问题所在。我认为 printf 会显示这个...
  • @R Samuel Klatchko。问题依然存在。请查看更新后的帖子
  • @everybody SegFault 出现在我添加的元素之后,他们已经在列表中!所以我认为错误是在 enter() 函数之后
【解决方案3】:

使用valgrind 之类的内容来查找此类问题。

【讨论】:

  • @twk:对不起,我不知道它是什么
  • @FILIaS 添加了指向@twk 所指套件的链接。
  • 谢谢你们俩,但作为初学者我不知道如何使用它
  • 另外,我的意思是最好的方式,但作为初学者,工作的一部分是学习如何使用新工具。把它想象成一种投资。它现在有成本,但它会在你的职业生涯中得到回报。
  • Valgrind 非常有用,只是在这种情况下不是。没有内存损坏,除非它发生在这段代码之外或条目太大而无法放入目录的固定大小条目中。虽然泄漏的可能性很高:o)
【解决方案4】:

退出 while 循环需要首先为空。在 else 语句中,您首先尝试访问。

【讨论】:

  • 所以我需要先用null初始化?但是在其他情况下会发生什么?
  • 您可以检查 first->next 是否为空,如果是,请不要将 first->next 分配给 first->next,只需跳出 while 循环即可。尽管基于其他 cmets 和通用代码,但您的意图似乎是在第二个!= NULL 或第一个 == NULL 时跳出循环。无论如何,您都想在最后的 else 中重新编写代码。
猜你喜欢
  • 2017-08-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多