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....
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
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);
Use something like valgrind to find problems like this.
Falling out of your while loop requires first to be null. In the else statement you attempt to access first.
Related
The particular problem I have is that in my main function, I have added a print statement before and after I call the "bad" function. It always shows the before statement, but never the after statement. I also added a print statement to the end of the "bad" function, and I can see that it runs properly to the very last line of the "bad" function, so it should return normally. After the functions last print and before the main function print, I get the segfault. Any ideas? Here is the code:
int main(int argc, char* argv[])
{
char myItem[100];
int i = 0;
while (i < 100) {
scanf("%[^\n]", myItem);
i++;
if (myItem == EOF) {
break;
}
int c;
while ((c = getchar()) != '\n' && c != EOF);
//printf("string read in from user typing: %s\n", myItem);
printf("i = %d\n", i);
emailFilter(myItem);
printf("done with email filter in main\n");
//printf("item from this pass is:%s\n\n", myItem);
}
return 0;
}
and the "bad" function:
void emailFilter(char* mySubject)
{
printf(" Just entered the emailFilter() .\n");
char * event_holder[5]; //holds five separate char ptrs
for (int i = 0; i < 5; i++)
{
event_holder[i] = ((char*)malloc(100 * sizeof(char*)));
}
char command_type = parseSubject(mySubject, event_holder); //parses subject line and fills event_holder. returns command type, from parsing
//call proper parsing result
if (command_type == 'C')
{
create(event_holder);
}
else if (command_type == 'X')
{
change(event_holder);
}
else if (command_type == 'D')
{
delete(event_holder);
}
printf("Leaving emailfilter()...\n");
}
and running this code provides me:
$:
i = 1
Just entered the emailFilter() .
C, Meeting ,01/12/2019,15:30,NEB202
Leaving emailfilter()...
done with email filter in main
i = 2
Just entered the emailFilter() .
Leaving emailfilter()...
Segmentation fault
This shows that I always make it through the function, but still don't return properly.
Here is my entire code to reproduce the error.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
char * event_data[5];
struct node * next;
};
struct node *head = NULL;
struct node *current = NULL;
char* earliest = NULL;
char* substring (char* orig, char* dest, int offset, int len)
{
int input_len = strlen (orig);
if (offset + len > input_len)
{
return NULL;
}
strncpy (dest, orig + offset, len);
//add null char \0 to end
char * term = "\0";
strncpy (dest + len, term, 1);
return dest;
}
char * firstItem(char* shortenedSubject)
{
int i = 0;
int currentLength = 0;
int currentCharIndex = 0;
int eventIndex = 0;
char * toReturn = (char*)malloc(100);
while ((shortenedSubject[currentLength] != '\0') && (shortenedSubject[currentLength] != ',') )//50 is my safety num to make sure it exits eventually
{
currentLength++;
}
if (shortenedSubject[currentLength] == ',') {
substring(shortenedSubject, toReturn, 0, currentLength);
}
return toReturn;
}
char parseSubject(char* subject,char * eventDataToReturn[5]) //returns "what type of command called, or none"
{
char toReturn;
char * shortenedSubject = (char*)malloc(100);
substring(subject,shortenedSubject,9,strlen(subject)-9);//put substring into tempString
int currentCharIndex = 0;// well feed into index of substring()
int eventIndex = 0; //lets us know which event to fill in
int currentLength = 0;//lets us know length of current event
int i = 0; //which char in temp string were alooking at
char * action = firstItem(shortenedSubject);
if (strlen(action) == 1)
{
if ( action[0] == 'C')
{
toReturn = 'C';
}
else if (action[0] == 'X')
{
toReturn = 'X';
}
else if (action[0] == 'D')
{
toReturn = 'D';
}
else
{
toReturn = 'N'; //not valid
//invalid email command, do nothing
}
}
else
{
toReturn = 'N'; //not valid
//invalid email command, do nothing
}
char* debug2;
while ((shortenedSubject[i] != '\0') && (i <= 50) )//50 is my safety num to make sure it exits eventually
{
char debugvar = shortenedSubject[i];
currentLength++;
if (shortenedSubject[i] == ',')
{
//eventDataToReturn[i] = substring2(shortenedSubject,currentCharIndex,currentLength);
substring(shortenedSubject,eventDataToReturn[eventIndex],currentCharIndex,currentLength-1);
debug2 = eventDataToReturn[eventIndex];
currentCharIndex= i +1;
eventIndex++;
currentLength = 0;
//i++;
}
i++;
}
substring(shortenedSubject,eventDataToReturn[4],currentCharIndex,currentLength);
return toReturn;
}
void printEventData(char* my_event_data[])
{
//printf("\nPrinting event data...\n");
for (int i = 1; i < 4; i++)
{
printf("%s,",my_event_data[i]);
}
//print last entry, no comma
printf("%s",my_event_data[4]);
}
void printEventsInorder()
{
struct node * ptr = head;
while (ptr != NULL)//if not empty, check each one and add when ready
{
printEventData(ptr->event_data);
printf("\n");
ptr = ptr->next;
}
}
void insertFront(char* my_event_data[5])
{
struct node *link = (struct node*) malloc(sizeof(struct node));
link->next = NULL;
for (int i = 0; i < 5; i++)
{
link->event_data[i] = my_event_data[i];
}
head = link;
}
int isEarlier(char* event_data_L[5], char* event_data_R[5])
{// will be given like 12:30 12:45,turn timeL into timeL1 and timeL2, and time R1 and timeR2
//compare dates for earlier
int month_L,day_L,year_L;
int month_R,day_R,year_R;
char* char_holder;
substring(event_data_L[2],char_holder,0,2);//extract first half of time
month_L = atoi(char_holder); //convert first half of time to int
substring(event_data_L[2],char_holder,3,2);//extract first half of time
day_L = atoi(char_holder); //convert first half of time to int
substring(event_data_L[2],char_holder,6,4);//extract first half of time
year_L = atoi(char_holder); //convert first half of time to int
substring(event_data_R[2],char_holder,0,2);//extract first half of time
month_R = atoi(char_holder); //convert first half of time to int
substring(event_data_R[2],char_holder,3,2);//extract first half of time
day_R = atoi(char_holder); //convert first half of time to int
substring(event_data_R[2],char_holder,6,4);//extract first half of time
year_R = atoi(char_holder); //convert first half of time to int
int time_L1,time_L2,time_R1,time_R2;
substring(event_data_L[3],char_holder,0,2);//extract first half of time
time_L1 = atoi(char_holder); //convert first half of time to int
substring(event_data_L[3],char_holder,3,2);//extract second half of time
time_L2 = atoi(char_holder); //convert second half of time to int
substring(event_data_R[3],char_holder,0,2);
time_R1 = atoi(char_holder);
substring(event_data_R[3],char_holder,3,2);
time_R2 = atoi(char_holder);
//convert to 2 ints, first compare left ints, then right ints
if(year_L < year_R)
{
return 1;
}
else if ( year_L == year_R)
{
if (month_L < month_L)
{
return 1;
}
else if (month_L == month_L)
{
if (day_L < day_R)
{
return 1;
}
else if (day_L == day_R)
{
if (time_L1 < time_R1)
{
return 1;
}
else if (time_L1 == time_R1)
{
if (time_L2 < time_R2)
{
return 1;
}
else if (time_L2 == time_R2)
{
return 2;
}
else//else, time is greater
{
return 3;
}
}
else //left time is greater, return 3
{
return 3;
}
}
else
{
return 3;
}
}
else
{
return 3;
}
}
else //its left is greater than right so return 3 to show that
{
return 3;
}
}
void create(char* my_event_data[5]) {
//print required sentence
char * debugvar2 = my_event_data[3];
if (head == NULL)//if empty calendar, just add it
{
insertFront(my_event_data);
//printf("EARLIEST bc empty list, \n");
printf("C, ");
printEventData(my_event_data);
printf("\n");
return;
}
else
{
struct node *link = (struct node*) malloc(sizeof(struct node));
link->next = NULL;
for (int i = 1; i < 5; i++)
{
link->event_data[i] = my_event_data[i];
}
struct node *ptr = head;
struct node *prev = NULL;
if (ptr->next == NULL) //if this is the last node to check against
{
if (isEarlier(my_event_data, ptr->event_data) == 1)
{ //check against it
printf("C, ");
printEventData(my_event_data);
printf("\n");
if (prev != NULL) //if this is first item in linked list...
{
link->next = head; //assign something before head
head = link; //move head to that thing
}
if (prev != NULL)
{
prev->next = link;
}
link->next = ptr;
return;
}
else //else is equal to or later, so tack it on after:
{
ptr->next = link;
}
}
else
{
while (ptr->next != NULL)//if not empty, check each one and add when ready
{
//if next node is later than current, we are done with insertion
if (isEarlier(my_event_data,ptr->event_data) == 1)
{
if (head == ptr) //if earlier than head... insert and print
{
//printf("earlier than head!");
printf("C, ");
printEventData(my_event_data);
printf("\n");
link->next = ptr;
head = link;
}
else //if earlier than non head, insert, but dont print
{
if (prev != NULL)
{
prev->next = link;
}
link->next = ptr;
}
return;
}
else
{
prev = ptr;
ptr = ptr->next;
}
}
if (isEarlier(my_event_data,ptr->event_data) == 1) //while ptr-> is null now
{
printf("C, ");
printEventData(my_event_data);
printf("\n");
if (prev != NULL)
{
prev->next = link;
}
link->next = ptr->next;
return;
}
else
{
prev = link;
link = ptr;
}
}
return;
}
//if it gets here, it is the latest meeting, tack it on the end
//prev->ptr = link;
}
void change(char* my_event_data[5]) {
//create a link
struct node *ptr = head;
while (ptr->next != NULL)//if not empty, check each one and add when ready
{
//if next node is later than current, we are done with insertion
if (*ptr->event_data[1] == *my_event_data[1])
{
for (int i = 1; i < 5; i++)
{
ptr->event_data[i] = my_event_data[i];
}
printf("X, ");
printEventData(my_event_data);
printf("\n");
return;
}
ptr = ptr->next;
}
if (*ptr->event_data[1] == *my_event_data[1]) //check final node
{
for (int i = 0; i < 5; i++)
{
ptr->event_data[i] = my_event_data[i];
}
printf("X, ");
printEventData(my_event_data);
printf("\n");
return;
}
printf("event to change not found");
return;
//if it gets here, nothing matched the title to change
}
void delete(char* my_event_data[5])
{
struct node *ptr = head;
struct node *prev = NULL;
while (ptr != NULL)//if not empty, check each one and add when ready
{
//if next node is later than current, we are done with insertion
if ( strcmp( ptr->event_data[1], my_event_data[1] ) == 0) // if title matches, delete it
{
if (prev != NULL)
{
prev->next = ptr->next;
}
if (ptr == head)
{
head = ptr->next;
}
free(ptr);
printf("D, ");
printEventData(my_event_data);
printf("\n");
return;
}
prev = ptr;
ptr = ptr->next;
}
}
void emailFilter(char* mySubject)
{
if (strlen(mySubject) < 9)
{
return;
}
char * event_holder[5]; //holds five separate char ptrs
for (int i = 0; i < 5; i++)
{
event_holder[i] = ((char*)malloc(100 * sizeof(char*)));
}
char command_type = parseSubject(mySubject, event_holder); //parses subject line and fills event_holder. returns command type, from parsing
//call proper parsing result
if (command_type == 'C')
{
create(event_holder);
}
else if (command_type == 'X')
{
change(event_holder);
}
else if (command_type == 'D')
{
delete(event_holder);
}
}
int main(int argc, char* argv[])
{
char myItem[100];
int i = 0;
while (i < 100)
{
scanf("%[^\n]", myItem);
i++;
if ( myItem == EOF )
{
break;
}
int c;
while ((c = getchar()) != '\n' && c != EOF);
printf("i = %d\n", i);
emailFilter(myItem);
}
return 0;
}
Also please note that this error happens when I use a txt file as STDIN via the ">" symbol on the command line. Here is the file I use:
Subject: C,Meeting ,01/12/2019,15:30,NEB202
Subject: C,Meeting ,01/12/2019,16:30,NEB202
Subject: C,Meeting ,01/12/2019,11:30,NEB202
Having tried to find something to contribute, there's this:
The code is dealing with the date/time. Below is the declaration and use of a "destination buffer" into which is copied fragments of the string:
int isEarlier(char* event_data_L[5], char* event_data_R[5])
{// will be given like 12:30 12:45 // ....
//compare dates for earlier
int month_L,day_L,year_L;
int month_R,day_R,year_R;
char* char_holder;
substring(event_data_L[2],char_holder,0,2);//extract first half of time
month_L = atoi(char_holder); //convert first half of time to int
//...
Notice that char_holder isn't pointing anywhere in particular. UB...
While it represents a beginner's approach, it is actually painful to see code like this. Below is a more concise version of isEarlier() (untested.)
int isEarlier( char *ed_L[5], char *ed_R[5] ) {
char l[16], r[16];
memcpy( l + 0, ed_L[2][6],4 ); // YYYY
memcpy( l + 4, ed_L[2][0],2 ); // MM
memcpy( l + 6, ed_L[2][3],2 ); // DD
memcpy( l + 8, ed_L[3][0],2 ); // hh
memcpy( l + 10, ed_L[3][3],2 ); // mm
memcpy( r + 0, ed_R[2][6],4 ); // YYYY
memcpy( r + 4, ed_R[2][0],2 ); // MM
memcpy( r + 6, ed_R[2][3],2 ); // DD
memcpy( r + 8, ed_R[3][0],2 ); // hh
memcpy( r + 10, ed_R[3][3],2 ); // mm
int res = memcmp( l, r, 12 );
return res < 0 ? 1 : res == 0 ? 2 : 3;
}
Note: The sample data provided indicates 2 digits for both month and day, and is ambiguous as to "mm/dd" or "dd/mm" format. The offset values used here come from the OP code.
One way to reduce the possibility of bugs in code is to both write less but more capable code, if you can, and to perform "unit testing" on code that you write. Focus on one function at a time and do not use global variables. Another is to become as familiar as you can with the proven capabilities of functions in the standard library.
EDIT: Looking at this answer, it occurs to me that this function should, itself, be refactored:
void reformatDateTime( char *d, char *s[5] ) {
memcpy( d + 0, s[2][6],4 ); // YYYY
memcpy( d + 4, s[2][0],2 ); // MM
memcpy( d + 6, s[2][3],2 ); // DD
memcpy( d + 8, s[3][0],2 ); // hh
memcpy( d + 10, s[3][3],2 ); // mm
}
int isEarlier( char *ed_L[5], char *ed_R[5] ) {
char l[16], r[16];
reformatDateTime( l, ed_L );
reformatDateTime( r, ed_R );
int res = memcmp( l, r, 12 );
res = res < 0 ? 1 : res == 0 ? 2 : 3;
printf( "isEarlier() '%.12s' vs '%.12s' result %d\n", l, r, res ); // debug
return res;
}
and I can see that it runs properly
You contradict yourself, you say that it sometimes or always seg faults. It's rather unlikely that some C code would crash at the point of leaving a function, since there's no "RAII" and in this case no multi-threading either. A stack corruption could have destroyed the function return address however.
The best way of debugging is not so much about focusing on the symptom, as it trying to pinpoint where something goes wrong. You've already done as much, so that's most of the debug effort already done.
One way of debugging from there is step #1: stare at the function for one minute. After around 5 seconds: event_holder[i] = ((char*)malloc(100 * sizeof(char*))); Well that's an obvious bug. After some 30 seconds more: wait, who cleans up this memory? The delete function perhaps but why is it then executed conditionally? (Turns out delete doesn't free() memory though.) The function leaks memory, another bug. Then after one full minute we realize that parseSubject does a whole lot of things and we'll need to dig through that one in detail if we want to weed out every possible chance of bugs. And it will take a lot more time to get to the bottom of that. But we already found 2 blatant bugs just by glancing at the code.
Fix the bugs, try again, is the problem gone?
At another glance there's a bug in main(), myItem == EOF is senseless and shouldn't compile. This suggests that you are compiling with way too lax warning levels or ignoring warnings, either is a very bad thing. What compiler options are recommended for beginners learning C?
We might note that extensive use of "magic numbers" make the code hard to read. It is also usually a sure sign of brittle code. Where do these 5 and 9 and so on come from? Use named constants. We will also fairly quickly note the lack of const correctness in something that's only supposed to parse, not change data. And so on.
I didn't read the code in detail, but the overall lack of following best practices and 3 bugs found just by brief glances suggests there's a whole lot more bugs in there.
When I modify the linked list (based on the ID), it modifies the node successfully but deletes the rest of the list. The whole list stays only if I modify the most recent node that I've added to the list.
I know that the problem is at the end where it says:
phead=i;
return phead;
But I don't know how to fix it as I haven't found anything to help me, even though I'm sure it is simple to know why it is wrong.
struct ItemNode *modify1Item(struct ItemNode *phead){
int modID;
int lfound=0;
int lID;
char lDesc[30];
char lName[30];
double lUPrice;
int lOnHand;
struct ItemNode *i=phead;
printf("Enter the ID of the item that you want to modify\n");
scanf("%d", &modID);
while(i != NULL){
if(i->ID == modID){
break;
}
i= i->next;
}
if(i==NULL){
printf("An item with that ID wasn't found.\n");
return 0;
}
else{
printf("Enter new Name\n");
scanf("%s", lName);
strcpy(i->name, lName);
printf("Enter new Description\n");
scanf("%s", lDesc);
strcpy(i->desc, lDesc);
printf("Enter new Unit Price $\n");
scanf("%lf", &lUPrice);
i->uPrice = lUPrice;
printf("Enter new Number of Items On Hand\n");
scanf("%d", &lOnHand);
i->onHand = lOnHand;
}
phead=i;
return phead;
}
When I return it, i say head=modify1Item(phead);
I tested your code everything worked as expected. Without seeing your code, I can't comment much. But I think, for your code, the only time everything would get delete is if you assign the return value incorrectly. So this below is probably something close to your code. For the test code below, unless you modify it, the IDs are 0, 1, and 2. Oh and the reason why I commented only work for 0 to 9 is because I don't want to make up the entire char string so I used i ^ 48. Of which, 0 - 9 ^ 48 would turn into the correspondent ASCII code of 0 - 9. If you go beyond that, you may get weird result for that two string that all.
I just noticed that you use NULL in your search. Thus, I updated the code so the "next" of last index will be NULL otherwise if your code found nothing, it will run forever.
#include <stdio.h>
#include <string.h>
typedef struct ItemNode {
int ID;
int uPrice;
int onHand;
char name[30];
char desc[30];
struct ItemNode * next;
} ItemNode ;
struct ItemNode * modify1Item(struct ItemNode * phead){
int modID;
int lfound=0;
int lID;
char lDesc[30];
char lName[30];
double lUPrice;
int lOnHand;
struct ItemNode *i = phead;
printf("Enter the ID of the item that you want to modify\n");
scanf("%d", &modID);
while(i != NULL){
if(i->ID == modID){
break;
}
i = i->next;
}
if(i==NULL){
printf("An item with that ID wasn't found.\n");
return 0;
} else {
printf("Enter new Name\n");
scanf("%s", lName);
strcpy(i->name, lName);
printf("Enter new Description\n");
scanf("%s", lDesc);
strcpy(i->desc, lDesc);
printf("Enter new Unit Price $\n");
scanf("%lf", &lUPrice);
i->uPrice = lUPrice;
printf("Enter new Number of Items On Hand\n");
scanf("%d", &lOnHand);
i->onHand = lOnHand;
}
phead=i;
return phead;
}
int main(){
// only work for 0 - 9.
int index = 3;
ItemNode iArr[index];
for ( int i = 0; i < index; i++ ){
iArr[i].ID = i;
iArr[i].uPrice = i + i;
iArr[i].onHand = i * i;
iArr[i].name[0] = i ^ 48;
iArr[i].desc[0] = i ^ 48;
// If last index link back to first index.
// Updated: but for you usage case
// because of your search function
// last index should be NULL otherwise your
// search will run forever
if ( i < index - 1 ) iArr[i].next = &iArr[i + 1];
else iArr[i].next = NULL; // if change search method with unique ID then you can use -> &iArr[0];
}
// Mod 0
ItemNode * test = modify1Item(iArr);
printf("0 name: %s\n\n",iArr[0].name );
// Mod 1
ItemNode * test1 = modify1Item(iArr);
printf("1 name: %s\n\n",iArr[1].name );
// Mod 2
ItemNode * test2 = modify1Item(iArr);
printf("2 name: %s\n\n",iArr[2].name );
// Check if 0 is still there.
printf("0 name: %s\n\n",iArr[0].name );
return 0;
}
So I have a particular C program that works on my Mac when I compile and run. I also tested via ssh on my school's linux computers, and it runs fine. However, my friend, who has a PC, used PuTTY to access the linux computers, and with the exact same code, he always gets a seg fault while running the program. Why might this be?
The code is listed below. I have provided the entire code, but the issue, as we found through print statements, lies in the int counter = 0; line early on in the main block:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
typedef struct Nodes{
char firstName[40];
char lastName[40];
char townName[70];
struct Nodes* next;
} Node;
//-- create head global variable.
Node* head;
//-- check if a char array contains a dash (to check for the 9 digit zip code)
bool containsDash(char* string){
char *s;
s = strchr (string, '-');
if (s==NULL){
return false;
}
else{
return true;
}
}
//-- insert node after ptr, with given attributes.
void insertNodeAfter(Node* ptr, char* fName, char* lName, char* tName){
Node* newPtr = (Node*) malloc(sizeof(Node));
strcpy(newPtr->firstName, fName);
strcpy(newPtr->lastName, lName);
strcpy(newPtr->townName, tName);
newPtr->next = ptr->next;
ptr->next = newPtr;
}
//-- insert node before head.
Node* insertNodeBeforeHead(char* fName, char* lName, char* tName){
Node* ptr = (Node*) malloc(sizeof(Node));
strcpy(ptr->firstName, fName);
strcpy(ptr->lastName, lName);
strcpy(ptr->townName, tName);
ptr->next = head;
head = ptr;
return ptr;
}
//-- check if char array starts with start
bool startsWith(char *start, char *str){
size_t lenstart = strlen(start);
size_t lenstr = strlen(str);
if (lenstart > lenstr){
return false;
}
else{
return strncmp(start, str, lenstart) == 0;
}
}
//-- check if nodes have equal attributes.
bool nodesEqual(Node* first, Node* second){
if (strcmp(first->firstName, second->firstName) == 0 && strcmp(first->lastName, second->lastName) == 0 && strcmp(first->townName, second->townName) == 0){
return true;
}
else{
return false;
}
}
//-- delete ptr node
void deleteNode(Node* ptr){
if (nodesEqual(ptr, head)){
head = ptr->next;
free(ptr);
}
else{
Node* temp = head;
while(1){
if (nodesEqual(temp->next, ptr)){
temp->next = temp->next->next;
free(ptr);
break;
}
else{
temp = temp->next;
}
}
}
}
//-- delete node with the given first and last name
void deleteNodeByInfo(char* fName, char* lName){
if (head == NULL){
return;
}
Node* temp = head;
while(1){
if (strcmp(temp->firstName, fName) == 0 && strcmp(temp->lastName, lName) == 0){
deleteNode(temp);
break;
}
if (temp->next != NULL){
temp = temp->next;
}
else{
break;
}
}
}
//-- take the current attributes and make a node in the correct spot
void insertNodeInCorrectSpot(char* fName, char* lName, char* tName){
//-- take 2 pointers separated by one link, look for a spot to insert node between these pointers
Node* pointer = head;
Node* pointer2 = head;
if (pointer->next != NULL){
pointer2 = pointer2->next;
}
else{
pointer2 = pointer2->next;
}
if (strcmp(tName, pointer->townName) < 0){
Node* newHead = insertNodeBeforeHead(fName, lName, tName);
head = newHead;
}
else{
while(strcmp(tName, pointer2->townName) > 0){
if (pointer2->next != NULL){
pointer = pointer->next;
pointer2 = pointer2->next;
}
else{
pointer = pointer2;
break;
}
}
insertNodeAfter(pointer, fName, lName, tName);
}
}
//-- remove spaces at the end of a string
void removeSpacesAtEnd(char* input){
int end = strlen(input) - 1;
if (isspace(input[end])){
input[end] = '\0';
}
if (isspace(input[--end])){
removeSpacesAtEnd(input);
}
}
//-- print the attributes of a given node
void printNode(Node* pointer){
printf("%s", pointer->firstName);
// printf("%s", " ");
printf("%s", pointer->lastName);
// printf("%s", " ");
printf("%s\n", pointer->townName);
}
// -d is option for debug.
int main(int argc, char* argv[]){
int counter = 0; //-- keep counter to keep track of cycle
char *tempChar, *tempFName, *tempLName, *tempTName;
//-- create buffers to store first name, last name, town name
tempChar = (char*)malloc(100*sizeof(char));
tempFName = (char*)malloc(40*sizeof(char));
tempLName = (char*)malloc(40*sizeof(char));
tempTName = (char*)malloc(70*sizeof(char));
while(counter < 600){
fgets(tempChar, 100, stdin);
//-- remove newline delimiter
char *pos;
if ((pos=strchr(tempChar, '\n')) != NULL)
*pos = '\0';
//-- The text will always go in a cycle of 6. Use modular division to figure out what is in the line being read.
if (counter % 6 == 0){
strncpy(tempFName, tempChar, strlen(tempChar));
removeSpacesAtEnd(tempFName);
strcat(tempFName, " ");
}
else if (counter % 6 == 1){
strncpy(tempLName, tempChar, strlen(tempChar));
removeSpacesAtEnd(tempLName);
if (counter == 1){
size_t len = strlen(tempChar);
tempLName[len] = '\0';
}
strcat(tempLName, " ");
}
else if (counter % 6 == 3){
if (containsDash(tempChar)){
strncpy(tempTName, tempChar, strlen(tempChar)-15);
}
else{
strncpy(tempTName, tempChar, strlen(tempChar)-9);
}
removeSpacesAtEnd(tempTName);
strcat(tempTName, " ");
}
else if (counter % 6 == 4){
if (counter == 4){
head = (Node*) malloc(sizeof(Node));
strcpy(head->firstName, tempFName);
strcpy(head->lastName, tempLName);
strcpy(head->townName, tempTName);
}
else{
insertNodeInCorrectSpot(tempFName, tempLName, tempTName);
}
memset(tempFName, 0, strlen(tempFName));
memset(tempLName, 0, strlen(tempLName));
memset(tempTName, 0, strlen(tempTName));
}
memset(tempChar, 0, strlen(tempChar));
counter++;
}
}
I have no idea if this is the same problem your friend ran into. But after adding an inclusion of stdbool.h, I was able to get a segmentation fault on my mac by running it like this:
$ ./testit < /etc/group
It's faulting here:
//-- remove spaces at the end of a string
void removeSpacesAtEnd(char* input){
int end = strlen(input) - 1;
if (isspace(input[end])){
input[end] = '\0';
}
if (isspace(input[--end])){
removeSpacesAtEnd(input);
}
}
It's faulting on the input:
"# Note that this file is consulted directly only when the system i"
This line contains a space in the second-to-last position, but not the last position. This causes the removeSpacesAtEnd() function to recurse infinitely until it fills up the call stack.
The simplest fix would be to move the second "if" block inside the first, so that it only executes when the last character of the input was a space:
//-- remove spaces at the end of a string
void removeSpacesAtEnd(char* input){
int end = strlen(input) - 1;
if (isspace(input[end])){
input[end] = '\0';
if (isspace(input[--end])){
removeSpacesAtEnd(input);
}
}
}
After fixing that, the program now crashes for me here:
else if (counter % 6 == 3){
if (containsDash(tempChar)){
strncpy(tempTName, tempChar, strlen(tempChar)-15);
}
else{
strncpy(tempTName, tempChar, strlen(tempChar)-9); <-- Here
}
So, this program may have other problems.
You should learn how to use a debugger. It's really not hard and it will save you a lot of frustrating time. Here's how I used lldb, the OSX debugger, to figure out the second crash:
Compile the program with debugging symbols (-g):
$ gcc -g -o testit testit.c
$
Invoke the debugger on the "testit" program. On linux you'd use gdb instead of lldb, but the commands that I'm going to use here will be the same.
$ lldb testit
(lldb) target create "testit"
Current executable set to 'testit' (x86_64).
(lldb)
Run "testit < /etc/group":
(lldb) run < /etc/group
Process 40951 launched: '/Users/kherron/x/testit' (x86_64)
Process 40951 stopped
* thread #1: tid = 0xc882f9, 0x00007fff8bde3c69 libsystem_platform.dylib`_platform_bzero$VARIANT$Unknown + 41, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x100200000)
frame #0: 0x00007fff8bde3c69 libsystem_platform.dylib`_platform_bzero$VARIANT$Unknown + 41
libsystem_platform.dylib`_platform_bzero$VARIANT$Unknown:
-> 0x7fff8bde3c69 <+41>: rep
0x7fff8bde3c6a <+42>: stosb %al, %es:(%rdi)
0x7fff8bde3c6b <+43>: movq %rdx, %rax
0x7fff8bde3c6e <+46>: popq %rbp
(lldb)
Yeah, that's all gobbledygook to me too. Don't worry about it. Let's look at the stack of function calls that got it here. "bt" is "backtrace", which prints the call stack.
(lldb) bt
* thread #1: tid = 0xc882f9, 0x00007fff8bde3c69 libsystem_platform.dylib`_platform_bzero$VARIANT$Unknown + 41, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x100200000)
* frame #0: 0x00007fff8bde3c69 libsystem_platform.dylib`_platform_bzero$VARIANT$Unknown + 41
frame #1: 0x00007fff8e90e40d libsystem_c.dylib`stpncpy + 70
frame #2: 0x00007fff8e980f12 libsystem_c.dylib`__strncpy_chk + 38
frame #3: 0x0000000100001c20 testit`main(argc=1, argv=0x00007fff5fbffb70) + 752 at testit.c:201
frame #4: 0x00007fff8b56c5c9 libdyld.dylib`start + 1
(lldb)
Frame 3 looks like a line in your program. Let's look at it.
(lldb) up 3
frame #3: 0x0000000100001c20 testit`main(argc=1, argv=0x00007fff5fbffb70) + 752 at testit.c:201
198 strncpy(tempTName, tempChar, strlen(tempChar)-15);
199 }
200 else{
-> 201 strncpy(tempTName, tempChar, strlen(tempChar)-9);
202 }
203 removeSpacesAtEnd(tempTName);
204 strcat(tempTName, " ");
Okay, print the value of tempChar at the time.
(lldb) p tempChar
(char *) $0 = 0x0000000100104b80 "##"
To make the point clear, print out the value of the expression "strlen(tempChar)-9":
(lldb) p strlen(tempChar) - 9
error: 'strlen' has unknown return type; cast the call to its declared return type
error: 1 errors parsing expression
(lldb) p (int)(strlen(tempChar)) - 9
(int) $1 = -7
So, it's passing a negative length to strlen().
I am trying to print an array of linked lists. I am having trouble getting it to print. Here is my struct.
typedef struct VERTEXTAG
{
char c;
bool isvisited;
struct EDGETAG* p;
}VERTEX;
typedef struct EDGETAG
{
VERTEX* v;
struct EDGETAG* q;
//cookies rock
//I like cookies
}EDGE;
Here are my variable declarations
VERTEX v[100];
EDGE *e;
EDGE* temp;
int counter = 0;
int addcounter = 0;
int i = 0;
Here is where I try to create the linked lists. I have an even case and an odd case.
//even case
if(counter - i == 1 && flag == 0)
{
vertices[addcounter] = (char)c;
//printf("The vertice is %c :\n", vertices[addcounter]);
e = (EDGE*) malloc(sizeof(EDGE));
v[addcounter].p=e;
v[addcounter].c= (char)c;
v[addcounter].isvisited=false;
v[addcounter].p=NULL;
addcounter++;
}
//odd case
if(counter - i == 1 && flag == 0)
{
vertices[addcounter] = (char)c;
//printf("The vertice is %c :\n", vertices[addcounter]);
e = (EDGE*) malloc(sizeof(EDGE));
v[addcounter].p=e;
v[addcounter].c= (char)c;
v[addcounter].isvisited=false;
v[addcounter].p=NULL;
(*e).v= &v[addcounter];
e->q = NULL;
addcounter++;
}
Here is where I try to print my linked list. For some reason temp is equal to NULL so it is not printing. I know I am correctly passing my variables to each case with vertices array. It prints out correctly. I am not sure if I am correctly creating the linked list of arrays since it will not print out. Also the second print statement in the while loop creates a segmentation when I take it out of the while loop so the program can reach it.
temp = v[0].p;
if(temp == NULL)
{
printf("Temp is Null\n");
}
while(temp != NULL)
{
printf("While loop");
printf("%c", (*(*temp).v).c);
temp = temp->q;
}
printf("The vertice is %s :\n", vertices);
Your problem is likely here:
v[addcounter].p=e;
v[addcounter].c= (char)c;
v[addcounter].isvisited=false;
v[addcounter].p=NULL;
Why are you setting v[x].p to e, then setting it to NULL a few lines after? Later on when you try to access v[0].p, of course it's going to still be NULL.
I have a problem writing a code that should read usernames and put them in list. Every username should be connected to the number of times it has been entered. The problem occurs when entering the second username, my code places that username in the variable called first (where the first is kept). I guess I've done something wrong with the pointers, but I cannot find what. I am confused, in the end of one while loop the first one is the real first one, and when the program enters while again, variable first changes. How could that be? Please help me.
Thank you :)
typedef struct _user
{
char *name;
int counter;
struct _user *next;
} user;
int main() {
char userName [10];
int found = 0, go_on = 1;
user *first = NULL, *temp, *new;
while (go_on == 1) {
printf ("Username: ");
scanf("%s", userName);
if (first) {
// printf ("The first one in list: %s\n", first->name); - this prints the name of last username entered
for (temp = first; temp; temp = temp->next) {
if (strcmp (temp->name, userName) == 0) {
temp->counter++;
found = 1; }
if (found== 1) break;}
if (!found) {
new = (user*) malloc (sizeof(user));
new->name = userName;
new->counter = 1;
temp = new;
temp->next = NULL; } }
else {
new = (user*) malloc (sizeof(user));
new->name = userName;
new->counter = 1;
first = new;
first->next = NULL; }
printf ("Go on? (1/0)");
scanf("%d", &go_on);
printf ("Current list: ");
for (temp=first; temp; temp = temp->next)
printf("%s %d\n", temp->name, temp->counter);
//printf ("The first one in list: %s\n", first->name); - this prints the correct first
}
}
Your error, I think, is the userName array. You should allocate a new one for each element in your linked list. When you write new->name = userName;, you are not copying the name to the struct, you are making the struct point to your userName[10] array. As such every struct's actual "name" is storing only the single last name scanf-ed. That being said...
I generally prefer to write that kind of code with dedicated tools instead of logically embedding them in a loop construct:
Keeping your struct:
typedef struct _user
{
char *name;
int counter;
struct _user *next;
} user;
I would create a function that, given a properly constructed Sll returns a matching element:
function user *user_match_name(user *user_head, const ch *name)
{
user *cur_user = NULL;
/* look for a match */
for (cur_user = user_head ; cur_user ; cur_user = cur_user->next)
if(!strcmp(name,cur_user->name) return cur_user;
/* no match */
return NULL;
}
Then I usually prefer to have an Sll element builder:
function user *create_user(const ch *name)
{
user *new_user;
if(!(new_user = malloc(sizeof(user))))
printf("Error in allocation"); /* or better malloc error handling */
/* IMPORTANT: PROVIDE MEMORY FOR THE NAMES!!! */
if(!(new_user->name = malloc(sizeof(char)*256))) /* sizeof(char) is useless but I like to explicit it like that. And 256 should be enough a buffer could be better made */
printf("Error in allocation"); /* or better malloc error handling */
strncpy(new_user->name, name,256); /* not sure if I got the argument order right... */
new_user->counter = 0; /* or 1 depending on your prefered convention */
new_user->next = NULL;
return new_user;
}
It ease the debugging like you wouldn't believe! Then it's just a matter of rewriting your main function:
int main() {
char userName [10];
int found = 0, go_on = 1;
user *user_head = NULL, *new_user,*temp;
while (go_on == 1) {
printf ("Username: ");
scanf("%s", userName);
if( (new_user = user_match_name(user_head,userName)) )
++new_user->counter
else
new_user = create_user(userName);
/* Here we push on the Sll */
if(user_head){
new_user->next = user_head;
user_head = new_user;
} else {
user_head = new_user;
}
printf ("Go on? (1/0)");
scanf("%d", &go_on);
printf ("Current list: ");
for (temp = user_head; temp; temp = temp->next)
printf("%s %d\n", temp->name, temp->counter);
//printf ("The first one in list: %s\n", first->name); - this prints the correct first
}
}
Ahhhhhh! Much easier to read. Be mindful of: 1) I didn't compile check the code. The important ideas are there, leverage them. 2) Even in your previous implementation, you are white space vulnerable but that's somewhat another topic.
Or you could cimply fix it by doing:
typedef struct _user
{
char name[10];
int counter;
struct _user *next;
} user;
and strncpy(new->name,userName,10) instead of assigning the pointer.