views:

197

answers:

4

It seems at least weird to me... The program runs normally.But after I call the enter() function for the 4th time,there is a segmentation fault!I would appreciate any help.

With the following function enter() I wanna add user commands' datas to a list.

[Some part of the code is already posted on another question of me, but I think I should post it again...as it's a different problem I'm facing now.]

    /* 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;
    }
}

UPDATE: SegFault appears only when it gets on the 'else' loop of InsertSort() function. I observed that segmentation fault appears when i try to put on the list names that are after it. For example, if in the list exists:

[Name:b Surname:b Amount:6 Description:b] [Name:c Surname:c Amount:5 Description:c] [Name:d Surname:d Amount:4 Description:d] [Name:e Surname:e Amount:3 Description:e] [Name:g Surname:g Amount:2 Description:g] [Name:x Surname:x Amount:1 Description:x]

and i put: " x z 77 gege" there is a segmentation but if i put "x a 77 gege" it continues normally....

+4  A: 

Not sure what's causing the bug, but I did see this bad pattern:

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

sizeof(short_name) will be always the same thing (usually 4 for 32 bit platforms and 8 for 64 bit platforms) so is not the correct value to use here. You should be doing:

strncpy(short_name, curToken, strlen(curToken) + 1);
R Samuel Klatchko
Since the segfault happens when trying to copy a string which was "initialized" in this way, this is likely the problem. I would think that the printf's would show this...
BlueRaja - Danny Pflughoeft
@R Samuel Klatchko. Problem remains. Please see the updated post
FILIaS
@everybody SegFault comes when i add elements that are after those that they're alreasy on the list! So i think that the error is after enter() function
FILIaS
+1  A: 

Use something like valgrind to find problems like this.

twk
@twk: im sorry i have no idea what it is
FILIaS
@FILIaS Added a link to the suite @twk was referring to.
Michael Todd
Thanx both of u,but as a beginner I dont know how to use it
FILIaS
What platform are you using? Linux, mac, windows?
twk
Also, and I mean this in the best possible way, but as a beginner part of job is learning how to use new tools. Think of it as an investment. It has a cost now, but it will pay off for the rest of your career.
twk
@twk I'm using Linux.Thanx for the advice! I will keep it on mind!
FILIaS
okay, all you have to do is install valgrind, then (if the name of your executable is foo) run: valgrind ./foo It will tell you where you are first corrupting the memory, which might not be where you first crash.
twk
are you using a command line? How are you running the program that is crashing right now?
twk
Valgrind is immensely useful, just not in this case. There is no memory corrupted, unless it happens outside this piece of code or entries are too large to fit into catalog's fixed size entries. There is high probability of leaks though :o)
MaR
@FILLias -- yes, the terminal.
twk
A: 

Falling out of your while loop requires first to be null. In the else statement you attempt to access first.

Dale
@Dale. So i need to initialise first with null? But what happens then on the other cases?
FILIaS
You could check to see if first->next is null, in cases when it is, don't assign first to first->next, simply break out of while loop. Although based on other comments and the general code, it would seem that your intent is to break out of the loop when either second != NULL or first == NULL. Regardless you will want to rework the code in the final else.
Dale
+4  A: 

Can't post into comment, so here it goes:

  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!)
  }

In other words, your program will crash if it finds any entry that satisfy conditions inside the loop and set 'second'. (This triggers intended addition "inside" the list).

Ok ~ no time to wait for answer :o), in a case you want to enter "after" the 'second' change code to this:

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

explanation (S is 'second', N a 'newNode', A B just some exisiting entries in the list):

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
MaR
Now the question is - how do you want to insert new entry in such case? Guessing after the 'second'?
MaR
@MaR. Thanks! That's correct!
FILIaS