I have an array of structs I would like to write to a binary file. I have a write.c program and a read.c program. The write.c program seems to be working properly but when I run the read.c program I get a segmentation fault. I'm new to C so It would be great if someone could look over my code for any obvious errors. I promise it's not too long :)
write.c:
#include <stdlib.h>
#include <stdio.h>
struct Person
{
char f_name[256];
char l_name[256];
int age;
};
int main(int argc, char* argv[])
{
struct Person* people;
int people_count;
printf("How many people would you like to create: ");
scanf("%i", &people_count);
people = malloc(sizeof(struct Person) * people_count);
int n;
for (n = 0; n < people_count; n++)
{
printf("Person %i's First Name: ", n);
scanf("%s", people[n].f_name);
printf("Person %i's Last Name: ", n);
scanf("%s", people[n].l_name);
printf("Person %i's Age: ", n);
scanf("%i", &people[n].age);
}
FILE* data;
if ( (data = fopen("data.bin", "wb")) == NULL )
{
printf("Error opening file\n");
return 1;
}
fwrite(people, sizeof(struct Person) * people_count, 1, data);
fclose(data);
return 0;
}
read.c:
#include <stdlib.h>
#include <stdio.h>
struct Person
{
char f_name[256];
char l_name[256];
int age;
};
int main(int argc, char* argv[])
{
FILE* data;
if ((data = fopen("data.bin", "rb")) == NULL)
{
printf("Error opening file\n");
return 1;
}
struct Person* people;
fread(people, sizeof(struct Person) * 1/* Just read one person */, 1, data);
printf("%s\n", people[0].f_name);
fclose(data);
return 0;
}
Thanks for the help!
struct Person* people;
This allocates just a pointer to struct, but you don't have any allocated space for actual struct contents. Either use malloc similarly to your write program, or try something like:
struct Person people;
fread(&people, sizeof(people), 1, data);
You need to allocate memory for the person first. Change: struct Person* people; into struct Person* people = malloc(sizeof(struct Person));. And don't forget to free your memory at the end: free(people);.
You either need to malloc memory into the pointer variable people before you do the fread, or (easier) just read directly into a local variable:
struct Person people;
fread(&people, sizeof(struct Person) * 1/* Just read one person */, 1, data);
You need to allocate space for the data you are reading in:
people = malloc(sizeof(*people)*numPeople);
Related
I have an array of structs I would like to write to a binary file. I have a write.c program and a read.c program. The write.c program seems to be working properly but when I run the read.c program I get a segmentation fault. I'm new to C so It would be great if someone could look over my code for any obvious errors. I promise it's not too long :)
write.c:
#include <stdlib.h>
#include <stdio.h>
struct Person
{
char f_name[256];
char l_name[256];
int age;
};
int main(int argc, char* argv[])
{
struct Person* people;
int people_count;
printf("How many people would you like to create: ");
scanf("%i", &people_count);
people = malloc(sizeof(struct Person) * people_count);
int n;
for (n = 0; n < people_count; n++)
{
printf("Person %i's First Name: ", n);
scanf("%s", people[n].f_name);
printf("Person %i's Last Name: ", n);
scanf("%s", people[n].l_name);
printf("Person %i's Age: ", n);
scanf("%i", &people[n].age);
}
FILE* data;
if ( (data = fopen("data.bin", "wb")) == NULL )
{
printf("Error opening file\n");
return 1;
}
fwrite(people, sizeof(struct Person) * people_count, 1, data);
fclose(data);
return 0;
}
read.c:
#include <stdlib.h>
#include <stdio.h>
struct Person
{
char f_name[256];
char l_name[256];
int age;
};
int main(int argc, char* argv[])
{
FILE* data;
if ((data = fopen("data.bin", "rb")) == NULL)
{
printf("Error opening file\n");
return 1;
}
struct Person* people;
fread(people, sizeof(struct Person) * 1/* Just read one person */, 1, data);
printf("%s\n", people[0].f_name);
fclose(data);
return 0;
}
Thanks for the help!
struct Person* people;
This allocates just a pointer to struct, but you don't have any allocated space for actual struct contents. Either use malloc similarly to your write program, or try something like:
struct Person people;
fread(&people, sizeof(people), 1, data);
You need to allocate memory for the person first. Change: struct Person* people; into struct Person* people = malloc(sizeof(struct Person));. And don't forget to free your memory at the end: free(people);.
You either need to malloc memory into the pointer variable people before you do the fread, or (easier) just read directly into a local variable:
struct Person people;
fread(&people, sizeof(struct Person) * 1/* Just read one person */, 1, data);
You need to allocate space for the data you are reading in:
people = malloc(sizeof(*people)*numPeople);
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 have problem with quick sort. It should sort books with author's names. Here is the code
#include <stdio.h>
#include <stdlib.h>
struct book {
char title[80];
char autor[80];
int pages;
};
int comparator (const void * a, const void *b)
{
struct book * ia=(struct book*)a;
struct book * ib=(struct book*)b;
return (strcmp(ia->autor,ib->autor));
}
int main(int argc, char ** argv)
{
int c = 2;
int i;
//Pointer to array of struct pointers, malloc for 2 structs
struct book **ptr = (struct book*)malloc(c*sizeof(struct book));
for(i=0;i<c;i++) {
//malloc for every struct
//also, if I'm doing it right?
ptr[i] = (struct book*)malloc(sizeof(struct book));
printf("Title: ");
scanf("%s",ptr[i]->title);
printf("Autor: ");
scanf("%s",ptr[i]->autor);
}
for(i=0;i<c;i++) {
printf("Before Quick sort Autor: %s, Title: %s \n",ptr[i]->autor,ptr[i]->title);
}
qsort(ptr,2, sizeof(struct book), comparator);
printf("QSORT DONe...\n\n");
for(i=0;i<c;i++) {
printf("TEST");
printf("After quick sort: Autor: %s, Title: %s \n",ptr[i]->autor,ptr[i]->title);
}
return 0;
}
So program compiles but it reaches only to printf("TEST"); (TEST prints on screen) and then it crashes.
Did I destroy my array with that quick sort? Or what could happen?
Also could you check my code if it's ok? Especially what mallocs (really) do in my code, because I'm not sure if I used them properly.
Thanks!
There were some small issues and confusions:
1) You were missing #include <string.h> for strcmp
2) You were allocating an array of pointers, which is probably not what you meant to do. An array in C is a pointer to the first element of the array, therefore if you allocate using (struct book*) malloc(n * sizeof(struct book)) you're already allocating a full array of n books.
You could also allocate an array of pointers to books, in which case you'd need to assign each pointer to a newly allocated book.
So you could do either of the following (and your code is mixing both):
struct book** ptr = (struct book**) malloc(c * sizeof(struct book*));
struct book* ptr = (struct book*) malloc(c * sizeof(struct book));
In the first case, you need to allocate new books (and therefore the malloc inside the loop would make sense)
In the second case, you just use the array directly, which is what I changed the following code to do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct book {
char title[80];
char autor[80];
int pages;
};
int comparator(const void * a, const void *b)
{
struct book * ia = (struct book*)a;
struct book * ib = (struct book*)b;
return (strcmp(ia->autor, ib->autor));
}
int main(int argc, char ** argv)
{
int c = 3;
int i;
//Pointer to array of struct pointers, malloc for 2 structs
struct book* ptr = (struct book*) malloc(c*sizeof(struct book));
if (ptr == NULL) {
printf("Could not allocate data\n");
return 1;
}
for (i = 0;i<c;i++) {
printf("Title: ");
scanf("%s", ptr[i].title);
printf("Autor: ");
scanf("%s", ptr[i].autor);
}
for (i = 0;i < c;i++) {
printf("Before Quick sort Autor: %s, Title : %s \n", ptr[i].autor, ptr[i].title);
}
qsort(ptr, c, sizeof(struct book), comparator);
printf("QSORT Done...\n\n");
for (i = 0;i<c;i++) {
printf("TEST");
printf("After quick sort: Autor: %s, Title: %s \n", ptr[i].autor, ptr[i].title);
}
free(ptr);
return 0;
}
3) Finally, it is a good practice to test the result of your malloc and to call free when you don't need it anymore.
It is shown for the point to be changed(for Pointer to array of struct pointers(but double pointer is not necessary)) following as
#include <string.h>
struct book * ia=*(struct book**)a;
struct book * ib=*(struct book**)b;
struct book **ptr = malloc(c*sizeof(struct book*));
qsort(ptr,2, sizeof(struct book*), comparator);
Perhaps version what you want
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct book {
char title[80];
char autor[80];
int pages;
};
int comparator (const void * a, const void *b)
{
struct book * ia=(struct book*)a;
struct book * ib=(struct book*)b;
return (strcmp(ia->autor,ib->autor));
}
int main(int argc, char ** argv)
{
int c = 2;
int i;
struct book *ptr = malloc(c*sizeof(struct book));
for(i=0;i<c;i++) {
printf("Title: ");
scanf("%s",ptr[i].title);
printf("Autor: ");
scanf("%s",ptr[i].autor);
}
for(i=0;i<c;i++) {
printf("Before Quick sort Autor: %s, Title: %s \n",ptr[i].autor,ptr[i].title);
}
qsort(ptr,2, sizeof(struct book), comparator);
printf("QSORT DONe...\n\n");
for(i=0;i<c;i++) {
printf("TEST");
printf("After quick sort: Autor: %s, Title: %s \n",ptr[i].autor,ptr[i].title);
}
return 0;
}
I'm going to give you an answer which will keep the definition of ptr, which is a pointer to a pointer to struct book, and also change a minimal amount of your code. This means we will allocate an array of pointers to struct book, and then for each pointer in that array we will allocate an actual object struct book.
The first malloc will allocate an array of cpointers to struct book:
struct book **ptr = (struct book**)malloc(c*sizeof(struct book*));
The for loop which allocates an object struct book using malloc is then correct.
The second correction is at the qsort() call. We are sorting pointers to struct book, not actual objects struct book.
qsort(ptr,4, sizeof(struct book*), comparator);
Then the comparison function needs a fix. Since we are sorting pointers, the comparison function will return a pointer to a pointer to struct book. So we need to dereference that pointer to our pointer to struct book:
int comparator (const void * a, const void *b)
{
struct book* ia=*(struct book**)a;
struct book* ib=*(struct book**)b;
return (strcmp(ia->autor,ib->autor));
}
i want to use nested structures with pointers in c. i write this code but i dont know why this code not working. actually how can i allocate memory for my second structure?
#include <stdio.h>
#include <stdlib.h>
struct address
{
int code;
char city[10];
};
struct student {
char name[10];
struct address *ads;
} *person1;
int main()
{
person1 = malloc(sizeof(struct student));
scanf("%s", person1->name);
scanf("%d", &person1->ads->code);
scanf("%s", person1->ads->city);
printf("%s", person1->name);
printf("%d", person1->ads->code);
printf("%s", person1->ads->city);
return 0;
}
NOTE: when i use "person1->ads = malloc(sizeof(struct address));" program ran to problem and stop working.
[Update from comment:]
I use DEV C++ v5.4.2
You need to also allocate memory for members stored via pointer.
int main()
{
person1 = malloc(sizeof(struct student));
person1->ads = malloc(sizeof(struct address));
scanf("%s", person1->name);
scanf("%d", &person1->ads->code);
scanf("%s", person1->ads->city);
printf("%s", person1->name);
printf("%d", person1->ads->code);
printf("%s", person1->ads->city);
free(person1->ads);
free(person1);
return 0;
}
You have a few poblems
You don't check the success of malloc.
You don't malloc for person1->ads member.
You don't check the success of scanf.
This is a fixed and anotated version of your code
#include <stdio.h>
#include <stdlib.h>
struct address
{
int code;
char city[10];
};
struct student
{
char name[10];
struct address *ads;
};
int main()
{
/* You don't need te struct to be global, and it's generally a bad idea, not always of course */
struct student *person;
/* you should check that malloc succeeded otherwise undefined behavior would happen */
person = malloc(sizeof(*person));
if (person == NULL)
{
printf("cannot allocate memory\n");
return -1;
}
/* you should check that scanf succeeded too */
if (scanf("%9s", person->name) != 1)
/* ^ prevent buffer overflow */
{
printf("Invalid, input\n");
free(person);
return -1;
}
person->ads = malloc(sizeof(*(person->ads)));
if (person->ads == NULL)
{
printf("cannot allocate memory\n");
/* on failure free successfuly allocated person */
free(person);
return -1;
}
/* you should check that scanf succeeded too */
if (scanf("%d", &person->ads->code) != 1)
{
printf("Invalid, input\n");
free(person->ads);
free(person);
return -1;
}
/* you should check that scanf succeeded too */
if (scanf("%9s", person->ads->city) != 1)
/* ^ prevent buffer overflow */
{
printf("Invalid, input\n");
free(person->ads);
free(person);
return -1;
}
printf("Name: %s\n", person->name);
printf("Code: %d\n", person->ads->code);
printf("City: %s\n", person->ads->city);
free(person->ads);
free(person);
return 0;
}
how can i allocate memory for my second structure?
For example the same way as you did for the first structure: allocate it from the heap
#include <stdlib.h>
#include <stdio.h>
struct address
{
int code;
char city[10];
};
struct student
{
char name[10];
struct address * ads;
};
int main(void)
{
struct student * person1 = malloc(sizeof * person1);
if (NULL == person1)
{
perror("malloc() failed for person1");
}
else
{
person1->ads = malloc(sizeof * person1->ads);
if (NULL == person1->ads)
{
perror("malloc() failed for person1->ads");
}
else
{
/* scan and print */
free(person1->ads);
}
free(person1);
}
}
I have this function that return a pointer to an allocated book inside this function, and the data comes from a file called book_saved.dat. I can compile this code but it sends me garbage, why?
book_saved is a file that already exists
*I have the struct in my original code.
#include <stdio.h>
#include <stdlib.h>
book_t *book_load(){
book_t *book;// book_t is a struct
book = (book_t*)malloc(sizeof(book_t));
if (book == NULL)
exit(1);
FILE*fp = fopen ("book_saved.dat", "rb");
fread (book, sizeof(book_t), 1, fp);
return book;
}
void print_book (book_t *book) {
printf("\n");
printf ("Book \nTitle: %s\nWriter: %s\nPublishing: %s\nYear: %d\nWeight %.1f\n", book->title, book->writer, book->publishing_house, book->year, book->weight);
}
int main (int argc, char *argv[]){
book_t *pontaux = book_load();
print_book (pontaux);
free (pontaux);
return 0;
}
Could you provide your writing function? I made a fairly basic one and it seems to work properly. I'd recommend sticking the struct in a shared header file just to make sure the structs used are absolutely the same, and also opening book_saved.dat in a hex editor to make sure the formatting in there's correct.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct book_t {
char title[75];
char writer [50];
char publishing[30];
int year;
float weight; // kg.
} book_t;
void book_make(){
book_t *book;// book_t is a struct
book = (book_t*)malloc(sizeof(book_t));
if (book == NULL)
exit(1);
strcpy(book->title, "Harry Potter: World\'s End");
strcpy(book->writer, "JK Rowlingbatman");
strcpy(book->publishing, "Publisherguy inc.");
book->year = 3000;
book->weight = 14.6;
FILE*fp = fopen ("book_saved.dat", "wb");
fwrite(book, sizeof(book_t), 1, fp);
fclose(fp);
}
book_t *book_load(){
book_t *book;// book_t is a struct
book = (book_t*)malloc(sizeof(book_t));
if (book == NULL)
exit(1);
FILE*fp = fopen ("book_saved.dat", "rb");
fread (book, sizeof(book_t), 1, fp);
return book;
}
void print_book (book_t *book) {
printf("\n");
printf ("Book \nTitle: %s\nWriter: %s\nPublishing: %s\nYear: %d\nWeight %.1f\n", book->title, book->writer, book->publishing, book->year, book->weight);
}
int main (int argc, char *argv[]){
book_make();
book_t *pontaux = book_load();
print_book (pontaux);
free (pontaux);
return 0;
}