Why am I getting a segmentationfault when it tries to print the second member in the list?
After printing the first element of the list, the debugger opens the stdio.h and says:
At C:\TDM-GCC-32\include\stdio.h:255
At C:\TDM-GCC-32\include\stdio.h:256
At C:\TDM-GCC-32\include\stdio.h:258
At C:\TDM-GCC-32\include\stdio.h:259
Here is the code.
#include <stdio.h>
#include <stdlib.h>
struct Student {
char *Name;
char *Adresse;
unsigned long Mtnr;
short Kurse;
struct Student *next;
struct Student *previous;
};
typedef struct Student Student;
Student *liste = NULL, *ende = NULL;
void add(char Name, char Adresse, unsigned long Mtnr, short Kurse) {
Student *add;
ende->next = malloc(sizeof(Student));
add = ende->next;
add->Name = Name;
add->Adresse = Adresse;
add->Mtnr = Mtnr;
add->Kurse = Kurse;
add->previous = ende;
add->next = NULL;
ende = ende->next;
}
void Ausgabe(Student *Anfang) {
while (Anfang != NULL) {
printf("%s %s %d %d \n", Anfang->Name, Anfang->Adresse, Anfang->Mtnr, Anfang->Kurse);
Anfang = Anfang->next;
}
}
int main() {
liste = malloc(sizeof(Student));
ende = liste;
liste->Name = "Anna Musterfrau";
liste->Adresse = "Am Schwarzberg-Campus 3";
liste->Mtnr = 22222;
liste->Kurse = 2;
liste->next = NULL;
liste->previous = NULL;
add("Hans Peter", "Kasernenstrasse 4", 4444, 4);
Ausgabe(liste);
return 0;
}
The error is in the declaration of the add() function. The strings should be char pointers, not chars.
void add(char *Name, char *Adresse, unsigned long Mtnr, short Kurse){
The signature of the function add is inconsistent to the declaration and usage to the members of Student. Change the signature as follows.
void add(char* Name, char* Adresse, unsigned long Mtnr, short Kurse)
On the long run, it might also be necessary to create copies of Name and Adresse in add, as the caller of add might deallocate them, perhaps causing undesired behaviour.
While Marc Is correct with his observation, there is one more thing you may want to fix here.
When you add a record, you allocate it, but you do not allocate the content of it's pointers (Specifically = for the name and address pointers). The add function just point them to the input's address. this is a problem because the data in the address supplied to the add function is likely to change if, for example, it's a user input, or some other external buffer.
in the code snipped below I fixed the 'name', but left the address as is. please run it and see what happens. (assaf's record displays david's address)
hope this helps
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student {
char *Name;
char *Adresse;
unsigned long Mtnr;
short Kurse;
struct Student *next;
struct Student *previous;
};
typedef struct Student Student;
Student *liste = NULL, *ende = NULL;
void add(char *Name, char *Adresse, unsigned long Mtnr, short Kurse) {
Student *add;
ende->next = malloc(sizeof(Student));
add = ende->next;
add->Name = malloc(strlen(Name)+1);
strcpy(add->Name, Name);
add->Adresse = Adresse;
add->Mtnr = Mtnr;
add->Kurse = Kurse;
add->previous = ende;
add->next = NULL;
ende = ende->next;
}
void Ausgabe(Student *Anfang) {
while (Anfang != NULL) {
printf("%s %s %d %d \n", Anfang->Name, Anfang->Adresse, Anfang->Mtnr, Anfang->Kurse);
Anfang = Anfang->next;
}
}
int main() {
char name_buf[100];
char address_buf[100];
liste = malloc(sizeof(Student));
ende = liste;
liste->Name = "Anna Musterfrau";
liste->Adresse = "Am Schwarzberg-Campus 3";
liste->Mtnr = 22222;
liste->Kurse = 2;
liste->next = NULL;
liste->previous = NULL;
add("Hans Peter", "Kasernenstrasse 4", 4444, 4);
sprintf(name_buf,"assaf stoler");
sprintf(address_buf,"maria 8");
add(name_buf, address_buf, 8888, 8);
sprintf(name_buf,"david david");
sprintf(address_buf,"some street 9");
add(name_buf, address_buf, 9999, 9);
Ausgabe(liste);
return 0;
}
EDIT: Op asked some questions, and the comment space is limited, so I'll add below:
A pointer is just an object pointing somewhere in memory. it's size is fixed. the content it's pointing to will vary.
When you include a pointer to a string in a structure, the space where the string is kept need to be allocated / accounted for. it is not part of the sizeof(struct).
In your original example the pointers were pointing to constant strings (which reside in the static code, usually the data section, allocated by the compiler), which is why your original code was able to access the strings.
In a more realistic case, the input data is not part of the program data, but is received by some input method (which my *buf was to emulate). as such, pointing your name and address at it would break the program, as the pointer you point to may have it's content changed. therefor copying of the data (string / array) is needed, and since we copy the data, we need to allocate space for it, and point our (name/address) pointer at it.
Alternate option is to use non-pointer array for name and address as in:
struct Student {
char Name[20];
char Adresse[60];
unsigned long Mtnr;
...
}
In this scenario, sizeof (struct Student) would actually include all the space for those fields. you still need to use strcpy or memcpy, as well as check for and handle strings that are too long to fit in your pre-defined length.
Hope this helps
Related
Doing a relational data structures project where I organize things into a hashtable. So far I've made an insert and lookup method and have no errors. When I try to run the code however I get this:
"Inserting CSG touples"
"segmentation fault 11"
I assume I'm not mallocing something correctly but I can't figure out what and considering it is saying "inserting CSG touples" I don't think its a problem in my createHashTable function. Heres my code
header file: CSG.h
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct CSG{
char* Course;
char* StudentId;
char* Grade;
struct CSG *next;
}CSG;
typedef struct CSGHASH{
int size;
CSG** table;
}CSGHASH;
CSGHASH* createHashTable(int size);
int hash(int CN);
CSG* makeCSG(char* Course, char* StudentId, char* Grade);
void printCSG(CSG guy);
//void printCSGLIST(CSGLIST guy);
int toInt(char* x);
CSG* lookup(CSGHASH *hashtable, char* course, char* StudentId, char* grade);
int insert(CSG* newGuy, CSGHASH* hashtable);
CSG.c
CSGHASH* createHashTable(int size){
CSGHASH* hashtable = NULL;
if(size<1)
return NULL; // table cant be less than length of 1
if((hashtable = malloc(sizeof(CSGHASH*)))== NULL)
return NULL;
if((hashtable->table = malloc(sizeof(CSG*) * size)) == NULL)
return NULL;
for(int i = 0; i<size; i++){
hashtable->table[i] = malloc(sizeof(CSG));
hashtable->table[i] = NULL;
//hashtable->table[i]->next = NULL;
}
hashtable->size = size;
return hashtable;
}
int hash(int CN){
return CN%6;
}
CSG* makeCSG(char* Course, char* StudentId, char* Grade){
//struct CSG tempCSG = malloc(sizeof(CSG));
CSG* tempCSG = malloc(sizeof(CSG*));
strcpy(tempCSG->Course, Course);
strcpy(tempCSG->StudentId, StudentId);
strcpy(tempCSG->Grade, Grade);
return tempCSG;
}
void printCSG(CSG guy){
printf("course: %s\n", guy.Course);
printf("StudentId: %s\n", guy.StudentId);
printf("Grade: %s\n", guy.Grade);
}
// void printCSGLIST(CSGLIST guy){
// }
int toInt(char* x){
int count = 0;
for(int i = 0; i< strlen(x); i++)
count += (int) i;
return count;
}
CSG* lookup(CSGHASH *hashtable, char* course, char* StudentId, char* grade){
CSG* list;
unsigned int hashNum = hash(toInt(course));
for(list = hashtable->table[hashNum]; list!= NULL; list = list->next){
if(strcmp(StudentId, list->StudentId) == 0){
printf("Course: %s\n", list->Course);
printf("Student ID: %s\n", list->StudentId);
printf("Grade: %s\n", list->Grade);
return list;
}
}
printf("doesn't exist\n");
return NULL;
}
int insert(CSG* newGuy, CSGHASH* hashtable){
CSG* list;
CSG* currList;
unsigned int hashNum = hash(toInt(newGuy->Course));
list = malloc(sizeof(CSG));
currList = lookup(hashtable, newGuy-> Course, newGuy-> StudentId, newGuy-> Grade);
if(currList != NULL){
printf("already exists\n");
return 2;
}
list->Grade = strdup(newGuy->Grade);
list->StudentId = strdup(newGuy->StudentId);
list->Course = strdup(newGuy->Course);
list->next = hashtable->table[hashNum];
hashtable->table[hashNum] = list;
printf("CSG inserted\n");
return 0;
}
main file
/*
main4.c
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include"CSG.h"
int main(int argc, char *argv[]){
CSGHASH *testHash = createHashTable(47);
printf("inserting CSG tuples \n");
CSG* tuple1 = makeCSG("CSC101", "12345", "A+");
CSG* tuple2 = makeCSG("CSC101", "67890", "B");
CSG* tuple3 = makeCSG("EE200", "67890", "B+");
CSG* tuple4 = makeCSG("EE200", "45213", "D");
CSG* tuple5 = makeCSG("CSC173", "98765", "C");
CSG* tuple6 = makeCSG("MTH142", "47474", "A");
insert(tuple1, testHash);
lookup(testHash, "CSC101", "12345", "*");
//printCSGLIST(lookup(tester, "CSC101", "12345", "*"));
}
If someone can figure out what I'm doing wrong I'd really appreciate it (sorry I know its a lot to trace through).
UPDATE
after a little debugging it would appear the issue is in the makeCSG function. Hope that makes it a little easier to trace through
A fast pass turned up:
if((hashtable = malloc(sizeof(CSGHASH*)))== NULL)
Err, this will allocate enough storage for a pointer to the CSGHASH and not the CSGHASH itself. Think you want to get rid of the asterisk. The following malloc() will also suffer the same fate.
From CSG.h:
typedef struct CSG{
char* Course;
char* StudentId;
char* Grade;
struct CSG *next;
}CSG;
and in makeCSG() you are doing:
CSG* makeCSG(char* Course, char* StudentId, char* Grade){
//struct CSG tempCSG = malloc(sizeof(CSG));
CSG* tempCSG = malloc(sizeof(CSG*));
strcpy(tempCSG->Course, Course);
strcpy(tempCSG->StudentId, StudentId);
strcpy(tempCSG->Grade, Grade);
return tempCSG;
}
There are couple of problems in makeCSG():
First problem:
CSG* tempCSG = malloc(sizeof(CSG*));
Here, tempCSG is a pointer pointing to CSG. So you should:
CSG* tempCSG = malloc(sizeof(CSG));
Similar issue in createHashTable():
if((hashtable = malloc(sizeof(CSGHASH*)))== NULL)
this should be:
if((hashtable = malloc(sizeof(CSGHASH)))== NULL)
Second problem:
strcpy(tempCSG->Course, Course);
strcpy(tempCSG->StudentId, StudentId);
strcpy(tempCSG->Grade, Grade);
Here, Course, StudentId and Grade are of type char * and you are trying to copy some value to pointers whom you have not allocated memory. Allocate memory before using them.
So first you should do something like this:
CSG* tempCSG = malloc(sizeof(CSG));
tempCSG->Course = malloc(100);
tempCSG->StudentId = malloc(20);
tempCSG->Grade = malloc(10);
and then
strcpy(tempCSG->Course, Course);
strcpy(tempCSG->StudentId, StudentId);
strcpy(tempCSG->Grade, Grade);
tempCSG->next = NULL;
Also, make sure to check the malloc return after every malloc call.
Basically everything envolving char* is wrong. You are not allocating the memory necessary to copy data into those buffers, in fact you are not initializing them at all.
A simplified version of whats wrong with your code:
char* Course;
strcpy(Course, "CSC101");
This is bond to cause fatal errors because we never allocated Course.
You have to either malloc() enough space to fit data in there, for each one of the char* in the structure, or declare them as arrays, so they are already allocated as you reserve memory for the structure they are in, but will have a fixed size determined at compile time.
Example:
typedef struct CSG
{
char Course[16];
char StudentId[16];
char Grade[16];
struct CSG *next;
} CSG;
This really is the easiest way to approach the problem, allows easy store and recover of this structure on a file if you wish to create some sort of basic database, and keeps the code cleaner, avoiding excessive memory management from a ton of malloc() and free() all over the place.
I need to understand why give this error message "stop working". Here is my code.
#include <stdio.h>
struct student{
int id;
char name[20];
char *title;
};
int main()
{
struct student *st;
st->id = 23;
//st->name = "shaib";
st->title = "title";
printf ("%d", st->id);
printf ("%s", st->title);
return 0;
}
You define a pointer but it is not init, so is Undefined Behavior.
You can create a space in heap memory using malloc function.
int main()
{
struct student *st = malloc(sizeof(struct student));
if ( st != NULL)
{
st->id = 23;
..
}
else
{
fprintf(stderr, "No space for variable\n");
}
free(st);
return 0;
}
As you can see, each time you allocate memory with malloc you are responsible for freeing it. Otherwise you have memory leak
Second problem is that
st->name = "shaib";
is not the way you fill an array with a C-String.
You can achieve it with:
strcpy(st->name, "shaib");
So, you need to allocate some memory for your new struct:
1) Add a #include in order to...
2) Replace the struct declaration for a malloc()
Tip: use a better format for your print outputs with \t and \n
Here's the working code:
#include <stdio.h>
#include <stdlib.h>
struct student{
int id;
char name[20];
char *title;
};
int main()
{
struct student *st = malloc(sizeof (struct student));
st->id = 23;
//st->name = "shaib";
st->title = "title";
printf ("%d\t", st->id);
printf ("%s\n", st->title);
return 0;
}
You're creating a pointer to the student structure, but you're not setting it to point to anything.
You'll need to allocate memory for st (the student structure) before you can use it.
You are not allocating memory for st.
You can do it like this: st = malloc(sizeof (student));
I have a task to make something that looks like Hotel Booking program in C.
Basically I should have 2 structures, one for reservations of rooms in the hotel (that contains information about that room like its ID, floor, how many beds are there and stuff like that, pointer to person that reserved the room and list of people that will be in that room) and the other structure for persons (which contains, lets say, name and surname of person).
The problem I am having is segmentation fault that I get since I probably didn't make those structures right.
Here is a part of my code, that is supposed to add a guest inside the list (that is located in reservation structure):
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#define MAXSTR 25
#define FORMAT_LEN 15
typedef struct person //structure that holds info about person
{
char name[MAXSTR + 1];
char surname[MAXSTR + 1];
}Guest;
typedef struct persons // list of persons
{
Guest person;
struct persons* next;
} Persons;
typedef struct //Pointer to first person in list
{
Persons* list;
} List;
typedef struct room //structure that holds info about rooms that are reserved
{
unsigned int ID;
unsigned int floor;
unsigned int bedcount;
struct tm dateArrival;
struct tm dateDep;
bool cancelled;
unsigned int price;
Guest* person;
List* list;
}Reservation;
typedef struct rooms
{
Reservation room;
struct rooms* next;
} Reservations;
bool PutGuestInsideList(List* list);
char* EnterString(char* str);
int main()
{
Reservations* room = NULL;
List list = { NULL };
printf("New guest: \n");
if(PutGuestInsideList(room->room.list) == false)
printf("Try again. \n");
}
bool PutGuestInsideList(List* list)
{
if(list == NULL)
return false;
Persons* newpers = (Persons*) malloc(sizeof(Persons));
if(newpers == NULL)
return false;
printf("Name: ");
EnterString(newpers->person.name);
printf("Surname: ");
EnterString(newpers->person.surname);
list->list = newpers;
return true;
}
char* EnterString(char* str)
{
if (str == NULL)
return str;
char format[FORMAT_LEN] = "";
sprintf(format, "%%%u[^\n]", MAXSTR);
scanf(format, str);
scanf("%*[^\n]");
scanf("%*c");
return str;
}
If there is something I left out in my explanation ask me in the comments. Thanks!
In main :
int main()
{
Reservations* room = NULL;//here you initialise pointer with NULL
List list = { NULL };
printf("New guest: \n");
if(PutGuestInsideList(room->room.list) == false)// and here you try to access it
printf("Try again. \n");
}
At if statement you are accessing member room.list on pointer room even if room is NULL.
BTW: Use (or learn to use) debugger, you will be able to debug your programs faster.(that's why they are called debuggers)
You dereferenced room which is NULL in the line if(PutGuestInsideList(room->room.list) == false). You can not dereference a NULL pointer. The room pointer should be properly set in your main function.
I think you need to spend some time on google looking up tutorials on pointers in C. As others are pointing out, room is set to null but you dereference it.
Reservations* room = NULL;
// and then
if(PutGuestInsideList(room->room.list) == false)
you also need to review these lines:
EnterString(newpers->person.name);
EnterString(newpers->person.surname);
Neither person.name nor person.name is given a buffer to write in. They are pointers which do not point anywhere but you attempt to use them.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to fill a struct with strings.
struct person {
char *name
char age
};
int record_values(struct person *dude, const char *his_name, char his_age)
{
dude->name = malloc(strlen(his_name)*sizeof(char)); //Get space for name
strcpy(dude->name, his_name); //Set name
strcpy(dude->age, his_age); //Set age
}
However this doesn't work. Any help?
dude->name = malloc(strlen(his_name)*sizeof(char)); //Get space for name
strcpy(dude->name, his_name); //Set name
strcpy(dude->age, his_age); //Set age
Your first line doesn't allocate enough space. You need one byte for the string terminator.
Your last line calls strcpy, but his_age is not a string.
int record_values(struct person *dude, const char *his_name, char his_age)
{
dude->name = strdup(his_name); // Duplicate name
dude->age = his_age; // Set age (Simple assignment!)
}
Instead of giving pointers on what you should change in your code here an complete working example that hopefully shows the required differences. The code below first creates an struct person but when the function record_values() is called you'll see that it first has to check if dude-name is not pointing to an char array already. Not having this check would create a memory leak in your code and the previous dude->name will never be freed. Also it allocates one extra char space in the char array for the string terminator (strcpy will copy it as well). This will avoid overflow errors. The function returns nothing, so make it an void functions rather than an function returning an int. The value of dude->age is not a pointer to memory space, therefore strcpy should not be used but dude->age = his-age which copies the values of variables.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct person {
char *name;
char age;
};
struct person * record_alloc(const char *his_name, char his_age);
void record_values(struct person *dude, const char *his_name, char his_age);
void record_free(struct person * dude);
struct person * record_alloc(const char *his_name, char his_age){
struct person * dude;
dude = malloc(sizeof(struct person));
if (his_name != NULL){
record_values(dude, his_name, his_age);
} else {
dude->age = 0;
dude->name = NULL;
}
return dude;
}
void record_values(struct person *dude, const char *his_name, char his_age)
{
size_t nameSize;
if (dude->name)
free(dude->name);
nameSize = (strlen(his_name) + 1) * sizeof(char);
dude->name = malloc(nameSize);
strcpy(dude->name, his_name);
dude->age = his_age;
return;
}
void record_free(struct person * dude){
if (dude->name)
free(dude->name);
free(dude);
return;
}
int main(int argc, const char * argv[]) {
struct person * p;
// allocate and set values
p = record_alloc("John Smith", 32);
printf("%s is %i years old\n", p->name, p->age);
// set new values for p
record_values(p, "John Doe", 37);
printf("%s is %i years old\n", p->name, p->age);
// free p
record_free(p);
return 0;
}
You might prefer to use designated initializers:
#include <stdio.h>
#include <string.h>
typedef struct {
char *name;
char age;
} person;
int record_values(person *dude, const char *his_name, char his_age)
{
*dude = (person) {.name = strdup(his_name), .age = his_age};
}
int main()
{
person p;
record_values(&p, "bob", 27);
printf("Hello, I am %s and I am %d years old!\n", p.name, p.age);
return 0;
}
Hello, I am Bob and I am 27 years old!
Since strdup is not a part of c99 your compiler might generate warnings, to get rid of them you need to compile it with -std=gnu99:
gcc -std=gnu99 -o main *.c
Or use your own version of this, which might look like this:
#include <stdlib.h>
char * strdup(const char *in) {
char *out = malloc(sizeof(in) + 1);
int i;
for (i = 0; in[i] != '\0'; ++i)
out[i] = in[i];
return out;
}
Hie guys. I am studying structures and pointers using the book called Pointers in C: A Hands on Approach and on page 107, I came across an incomplete example of struct type casting. I tried to make it work by just implementing the function receivedata() ,adding headers and making a few changes.
This is the complete code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct signature
{
char sign;
char version;
};
struct id
{
char id;
char platform;
};
struct data
{
struct id idv;
struct signature sig;
char data[100];
};
static void receivedata(struct data *d);
static struct signature *extractsignature(struct data *d);
static struct id *extractid(struct data *d);
int main(int argc, char *argv[])
{
/* Actual line in book is :
* struct data *img; with no memory allocation or assignment to NULL.
* Had errors so i allocated memory on the heap before passing the value to
* Receivedata(); */
struct data *img = malloc(sizeof(struct data));
receivedata(img);
/* Actual line in book is :
* struct id *idval = extractid(&img);
* struct signature *sig = extractsignature(&img);
* This is obviously erroneous because &img is a pointer
* to a pointer (struct data**) which is not the data type for
* the extract functions' argument */
struct id *idval = extractid(img);
struct signature *sig = extractsignature(img);
printf("For signature:\n");
printf("sign = %c", sig->sign);
printf(" version = %c\n\n", sig->version);
printf("For id:\n");
printf("id = %c", idval->id);
printf(" platform = %c", idval->platform);
printf("\ndata = %s", img->data);
return 0;
}
static struct signature *extractsignature(struct data *d)
{
struct signature *sig = (struct signature *)d;
return sig;
}
static struct id *extractid(struct data *d)
{
struct id *idv = (struct id *)d;
return idv;
}
static void receivedata(struct data *d)
{
struct data *dptr = d;
char *ch = "CODING IS COOL!";
dptr->sig.sign = 's';
dptr->sig.version = '1';
dptr->idv.id = 'i';
dptr->idv.platform = 'p';
strncpy(dptr->data, ch, strlen(ch));
return;
}
What I would like to understand is the casting inside the function extractid() and extraxtsignature() because it seems we are casting struct data * so as to retrieve its individual members. I ran the program and what i get is the value of the first member of struct data for both sig member and id members. Here is the output when struct id comes first in the struct data:
For signature:
sign = i version = p
For id:
id = i platform = p
data = CODING IS COOL!
and this when struct signature is the first element:
For signature:
sign = s version = 1
For id:
id = s platform = 1
data = CODING IS COOL!
and finally, this when char data[100] is the first element:
For signature:
sign = C version = O
For id:
id = C platform = O
data = CODING IS COOL!
May you please explain this type of casting, when to use it and the best practices. Thank you very much.
struct data
{
struct id idv;
struct signature sig;
char data[100];
};
For the above definition, the extractid function below is valid and will get right results.
static struct id *extractid(struct data *d)
{
struct id *idv = (struct id *)d;
return idv;
}
This is because, struct id is the first member of the struct data. So, when you have struct data *d, the d points to the starting address of struct data and which is same as the starting address of the first member struct id.
So, if you are casting for the first member of the struct, then it is right as per the code you have provided above.