C Segmentation fault - saving struct in .dat file - c

Can someone please tell me, what causes the segementation fault in my C - code? I am trying to save a struct into a file, and calling it afterwards, following this guide. I don't see anything assigned wrongly, so I'm happy to learn what's my mistake by someone more experienced.
Here is my code, simplified:
int main(int argc, char **argv)
{
char *key = (argc > 4) ? argv[4]: 0;
if(0==strcmp(key, "write")){
struct MyStruct s;
FILE *myoutfile;
myoutfile = fopen("file.dat","w")
if (myoutfile == NULL)
{
fprintf(stderr, "\nError opend file\n");
exit (1);
}
s = get_struct(argv[2]);
fwrite(&s, sizeof(struct MyStruct), 1, myoutfile);
fclose(myoutfile);
}else{
struct MyStruct t;
FILE *myinfile;
myinfile = fopen("file.dat", "r")
if (myinfile == NULL)
{
fprintf(stderr, "\nError opend file\n");
exit (1);
}
while (fread(&t, sizeof(struct MyStruct), 1, myinfile))
printf("Done reading");
}
work_with_struct(t);
fclose(myinfile);
}
Also, as I read in another stack overflow post, doing this:
fread(&t.one, sizeof(t.one), 1, myinfile);
fread(&t.two, sizeof(t.two), 1, myinfile);
fread(&t.three, sizeof(t.three), 1, myinfile);
did not work either.
EDIT: I now think i have located the problem a bit more. The first part of the function (if) works fine. What I thought was not necessary to mention first, was that in the end of the "else" I have a function that works with t. This is the one throwing the error, i believe.
It works fine, when I leave out the .dat-file-part, so by just saying
t = get_struct(argv[2]);
work_with_struct(t);
which I actually want to avoid, because "get_struct" is huge. Doing it once, and working with the data in the .dat file was my solution, that I calculate it only once.
My assumption now is, that putting the struct into the fstream and getting it back will somehow destroy it, or makes it somehow not-readable for work_with_struct. What I think is also worth mentioning is, that inside the struct there are three members: two char **, and one custom data type.
I didn't find any other solution suggesting other ways of reading in the file.
Maybe with this explanation someone gets alerted, where the segmentation fault might come from. Thanks a lot!

The issue is that you are passing a NULL pointer to strcmp which expects a const char*. When no arguments are passed to the program key = 0 and the program segfaults because strcmp attempts to dereference this NULL pointer.
Edit:
I attempted to correct the example program to make it compile and run, here it is:
Edit 2: print content of saved struct
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
struct MyStruct {
int a;
};
int main(int argc, char **argv) {
const char *key = (argc > 4) ? argv[4] : "write";
if (0 == strcmp(key, "write")) {
struct MyStruct s;
FILE *myoutfile;
myoutfile = fopen("file.dat", "w");
if (myoutfile == NULL) {
fprintf(stderr, "\nError opend file\n");
exit(1);
}
s = (struct MyStruct){ 'a' };
fwrite(&s, sizeof(struct MyStruct), 1, myoutfile);
fclose(myoutfile);
} else {
struct MyStruct t;
FILE *myinfile;
myinfile = fopen("file.dat", "r");
if (myinfile == NULL) {
fprintf(stderr, "\nError opend file\n");
exit(1);
}
while (fread(&t, sizeof(struct MyStruct), 1, myinfile))
printf("Done reading\n");
printf("%c\n", t.a);
fclose(myinfile);
}
}
Edit 3:
After updating the description of the struct MyStruct the problem is obvious. You need to find a different way to save the struct to the file then by using fwrite since you have pointer types in it. The way you would go about that is a topic for a different question.

Related

How to Return Values From thread Back to main()

I am using pthread_create to create a thread that examines the amount of lines in a file, then returns the answer to the main thread. I have tried using pthread_join, and malloc() but I am new to both and must have used them improperly. If anyone knows how to pass an integer from a thread back to the main, please help. My code is below.
#include <pthread.h>
#include <stdio.h>
void *count_lines(void *arg)
{
FILE *fh= (FILE *) arg;
int num_lines=0;
char ch;
for(ch=getc(fh); ch!=EOF; ch=getc(fh))
if(ch=='\n')
num_lines=num_lines+1;
fclose(fh);
int* value = (int *)malloc(sizeof(int));
*value=10;
pthread_exit(value);
}
int main()
{
FILE *fh;
fh=fopen("data.txt", "r");
pthread_t my_thread;
pthread_create(&my_thread, NULL, count_lines, &fh);
void *retval;
pthread_join(my_thread, &retval);
int i = *((int *)retval);
free(retval);
printf("%d\n", i);
}
I am running an Ubuntu virtual machine and using Visual Studio Code if that is of any help. When I run the code above I get a "Core Dump (Segmentation Fault)" error. Again, an help is much appreciated.
You are making everything needlessly complicated. Make a struct such as this:
typedef struct
{
FILE* fp;
int ret_val;
} count_lines_type;
static count_lines_type cl;
cl.fp = fopen (...);
...
pthread_create(&my_thread, NULL, count_lines, &cl);
Fill in ret_val before the thread is done.
I made the struct instance static just in case the calling thread would go out of scope before the count lines thread is done. If it never does that, static isn't necessary.
Before you create a thread, check if the file is really opened:
fh=fopen("data.txt", "r");
if (fh == NULL) exit(1);
Also fh is already a pointer. You dont need to pass &fh (pointer to pointer) to thred create (you're expecting FILE* not FILE** in count_lines).
Also check if thread creation succeeded:
if (pthread_create(&my_thread, NULL, count_lines, fh) != 0)
exit(2); //error -> contents of my_thread is undefined in this case
Also check the retval (dereference only if valid pointer, otherwise segmentation error):
if (retval != NULL)
{
int i = *((int *)retval);
free(retval);
}

segmentation 11 in C

I'm writing a homework program in C. The program should take records from an input file and write those record to an output file. It seems like there is something wrong with the print_to_file function. I keep getting segmentation fault 11. Please help. My code is as below.
#include <stdio.h>
#include <stdlib.h>
typedef struct car { // create a struct type Car
char *license_plate;
int parking_spot;
int num_tickets;
int time_left;
} Car;
#define LICENSEPLATELENGTH 10
Car* import_cars(char *filename, int numCars);
void print_to_file(char* filename, Car* garage, int numCars);
int main(int argc, char * argv[]) {
if(argc != 4)
printf("Incorrect input.\n");
else {
int number = atoi(argv[1]);
Car* parked_car = (Car*)malloc(sizeof(Car) * number);
parked_car = import_cars(argv[2], number);
print_to_file(argv[3], parked_car, number);
free(parked_car);
}
return 0;
}
Car* import_cars(char* filename, int numCars)
{
Car* inCar = (Car*)malloc(sizeof(Car) * numCars);
inCar->license_plate = (char*)malloc(sizeof(char) * 8);
//Question: How do I do if I the plate length is varied. How to malloc space to it?
FILE* inFilePtr;
if((inFilePtr = fopen(filename, "r")) == NULL)
printf("Error! Unable to open file %s. Check again.\n", *filename);
else
{
int i = 0;
fscanf(inFilePtr, "%s", inCar[i].license_plate);
fscanf(inFilePtr, "%d%d%d", inCar[i].parking_spot, inCar[i].num_tickets, inCar[i].time_left);
printf("%s %d %d %d \n", inCar[i].license_plate, inCar[i].parking_spot, inCar[i].num_tickets, inCar[i].time_left);
for(i = 1; i < numCars; i++)
{
fscanf(inFilePtr, "%s", inCar[i].license_plate);
fscanf(inFilePtr, "%d%d%d", inCar[i].parking_spot, inCar[i].num_tickets, inCar[i].time_left);
printf("%s %d %d %d \n", inCar[i].license_plate, inCar[i].parking_spot, inCar[i].num_tickets, inCar[i].time_left);
}
}
fclose(inFilePtr);
return(inCar);
//free(inCar.license_plate); `
//Question: Do I need to free space here would it remove the value
//stored in the variable which passed to main?
}
void print_to_file(char* filename, Car* garage, int numCars) {
FILE* outFilePtr;
if((outFilePtr = fopen(filename, "w+")) == NULL){
printf("Error! Cannot Open File %s!", *filename);
printf("here\n");
} else {
int i = 0;
for(i = 0; i < numCars; i++) {
printf("%s\n%d %d %d\n", garage[i].license_plate, garage[i].parking_spot, garage[i].num_tickets, garage[i].time_left);
fprintf(outFilePtr, "%s\n%d %d %d\n", garage[i].license_plate, garage[i].parking_spot, garage[i].num_tickets, garage[i].time_left);
}
}
fclose(outFilePtr);
}
This is my input command.
./a.out 6 garage.txt output.txt
Here is what print in my terminal.
fi590dz 20 2 25
57fjgmc 8 0 55
7dkgjgu 25 1 15
f9e829d 1 2 60
4jgfd81 12 2 10
Segmentation fault: 11
By the way, I'm pretty new in programming and really bad with debugging. Could you give me some tips of how to debug or any debugging tools? I use a mac so gdb doesn't work.
Not a complete answer, because it’s a homework problem and you want to figure it out yourself, but here are some hints.
First, you really want to learn how to run your program in a debugger and get it to tell you which line crashed the program, and on which data.
Second, make sure you initialize the pointers for every element of the array before you try to read or write them.
Third, you’ll save yourself a lot of trouble if you initialize all your dynamic and local variables to zeroes, not garbage. It will make a lot of bugs reproducible, make a lot of bugs crash immediately instead of corrupting memory, and also make it obvious when you debug that you’re using uninitialized data.
Therefore, I suggest you get in the habit of allocating your dynamic arrays with calloc(), not malloc().
The problem lies within your parked_car = import_cars(argv[2], number); and Car* import_cars(char* filename, int numCars);functions.
Indeed in Car* import_cars(char* filename, int numCars); you are doing this:
Car inCar;
inCar.license_plate = (char*)malloc(sizeof(char) * 8);
So you are creating a local variable that is not accessible outside of the function (many different things can happen to the memory after the end of the function).
So when you do: parked_car = import_cars(argv[2], number); you are assigning to parked_car a freed variable.
A solution is to simply use the parked_caras an argument of your import_cars() function. All modifications made within the function will still be valid after it returns. So you should have:
void import_cars(char* filename, int numCars, Car* car);
For everyone who met the issue here, I found the problem in my program. The problem is that I didn't allocate space for each of the license_plate pointer in the structure. So my way to solve it is add a line as below in the for loop of the import_cars function.
inCar[i].license_plate = (char*)malloc(sizeof(char) * LICENSEPLATELENGTH);

problems about insert some data to a file

I write a function to insert some data to a file. And it works fine when i only use it once. but when i wrote a loop to test this function, the program crashed. how can i fix this?(sorry for my terrible English, i promise i will try to improve it^_^)
here is the code(written in C)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int finsert(char *insert,int size,long offset,FILE *fp,int memory);
int main()
{
FILE *fp;
FILE *record;
char insert[100]="2";
long start,end;
int i=0;
if((fp=fopen("test","rb+"))==NULL)
{
printf("error!\n");
exit(1);
}
if((record=fopen("record.txt","w+"))==NULL)
{
printf("error!\n");
exit(1);
}
for(i=1;i<=10000;i+=1)
{
start=clock();
finsert(insert,strlen(insert),0,fp,i);
end=clock();
fprintf(record, "%d,%ld\n",i,end-start);
printf("\ri=%d ",i);
}
fclose(fp);
fclose(record);
return 0;
}
/*
this is the function and int memory is how many data to write to the file everytime
*/
int finsert(char *insert,int size,long offset,FILE *fp,int memory)
{
long i;
long getsize=size;
long writesize=size;
char *read;
char *write;
char *fill;
char *read_keep;
char *write_keep;
char *fill_keep;
long offset_read,offset_write;
if(size>=memory)
{
read=(char *) malloc(size);
write=(char *) malloc(size);
read_keep=read;
write_keep=write;
strcpy(write,insert);
while(getsize==size)
{
fseek(fp,offset,SEEK_SET);
getsize=fread(read,1,size,fp);
fseek(fp,offset,SEEK_SET);
fwrite(write,1,writesize,fp);
offset+=getsize;
strcpy(write,read);
writesize=getsize;
}
fwrite(write,1,writesize,fp);
free(read_keep);
free(write_keep);
}
else
{
writesize=memory;
getsize=memory;
offset_write=offset;
offset_read=offset-size+memory;
read=(char *) malloc(memory+3);
write=(char *) malloc(memory+3);
fill=(char *) malloc(memory-size);
for(i=0;i<memory+3;i+=1)
{
read[i]=0;
write[i]=0;
}
if(read==NULL||write==NULL||fill==NULL)
{
printf("malloc error!\n");
exit(1);
}
strcpy(write,insert);
fseek(fp,offset,SEEK_SET);
fread(fill,1,memory-size,fp);
strcpy(write+size,fill);
while(getsize==memory)
{
fseek(fp,offset_read,SEEK_SET);
getsize=fread(read,1,memory,fp);
fseek(fp,offset_write,SEEK_SET);
fwrite(write,1,writesize,fp);
offset_read+=getsize;
offset_write+=getsize;
if(memory+1<strlen(read)) printf("copy error!\n");
strcpy(write,read);
writesize=getsize;
}
fwrite(write,1,writesize,fp);
free(read);
free(write);
free(fill);
}
}
maybe you could describe a bit more what your program is intended to do.
When I run it in valgrind, it reported quite a lot invalid memory reads and writes...
The fact is that it runs fine once, because after one run program is not able to destroy its memory so much, however if you run it 10000 time, damage is severe (causing SEGFAULT).
Most of memory overwrites happens here:
strcpy(write+size,fill);
and here:
strcpy(write,insert);
strcpy(write,read);
caused by:
read=(char *) malloc(size);
write=(char *) malloc(size);
I was not able to determine why it happens in first case, but in second case it looks to be obvious that parameter size will always be 1 byte and you need to least 2 bytes for copy string, as ti must be terminated by '\0'.
so might to change the code to something like:
read=(char *) malloc(size + 1);
write=(char *) malloc(size + 1);
And for following code:
for(i=0;i<memory+3;i+=1)
{
read[i]=0;
write[i]=0;
}
You might have a look on memset().
P.S
I was able to make it run removing last free(read); but this is hardly correct solution ...

lseek() and read() proper usage

I am reading in a "non human readable file" full of structs. I have declared my struct that is a known member of the file. I want to read the file from the begging to the sizeof the stuct populating the fields. I don't understand why my out put is zero for all the struct fields. I have looked at the man pages of these functions and I believe I am using them correctly, so am I just not accessing the fields correctly from the buffer, or? please see below code snippet.
int main (int argc, char * argv[])
{
// make sure you were given an image
if (argc != 2)
{
printf("no image\n");
return -1;
}
int fs_fd = open(argv[1], O_RDWR);
// make sure you can open the image
if(fs_fd == -1)
{
printf("image is busted\n");
return -1;
}
struct superblock *mySB;
mySB = malloc(sizeof(struct superblock));
mySB->size = 0;
mySB->nblocks = 0;
mySB->ninodes = 0;
char buffer[4096];
if(lseek(fs_fd, 0, SEEK_SET));
read(fs_fd, &buffer, sizeof(struct superblock));
mySB->size = buffer[0];
mySB->nblocks = buffer[4];
mySB->ninodes = buffer[8];
printf("Size: %u, nblocks: %u, ninodes: %u\n", mySB->size, mySB->nblocks, mySB->ninodes);
}
ok, suggestions taken into consideration, though in truth I'm not concerned withe good error checking at this point. the following results in a seg fault as i'm sure this is not reading into the struct correctly, but I am trying to use the suggestions.
int main (int argc, char * argv[])
{
// make sure you were given an image
if (argc != 2)
{
printf("usage: file.img");
return -1;
}
int fd = open(argv[1], O_RDWR);
// make sure you can open the image
if(fd == -1)
{
perror("Error> ");
return -1;
}
struct superblock *mySB;
mySB = malloc(sizeof(struct superblock));
read(fd, &mySB, sizeof(struct superblock));
printf("Size: %u, nblocks: %u, ninodes: %u\n", mySB->size, mySB->nblocks, mySB->ninodes);
}
Why no compilable testcase along with an example file?
int fs_fd = open(argv[1], O_RDWR);
// make sure you can open the image
if(fs_fd == -1)
{
printf("image is busted\n");
return -1;
}
Wrong. At the very least use perror to tell what the user what the error is. What's up fs_fd name anyway? Standard name is mere fd.
struct superblock *mySB;
mySB = malloc(sizeof(struct superblock));
Consider sizeof(*mySB);. Null-checks can arguably be ignored.
mySB->size = 0;
mySB->nblocks = 0;
mySB->ninodes = 0;
What's the point of this if you initialize same fields below?
char buffer[4096];
if(lseek(fs_fd, 0, SEEK_SET));
What? Not only teh offset is already at the beginning, you are just ignoring the error (if any) in the worst possible way. If you really need to call this and ignore the error, do (void)lseek(fd_fd, 0, SEEK_SET).
read(fs_fd, &buffer, sizeof(struct superblock));
How about some error checking. If you read only teh size of the struct, why having the buffer be 4096? What if the struct is larger?
mySB->size = buffer[0];
mySB->nblocks = buffer[4];
mySB->ninodes = buffer[8];
Nobody knows how this struct looks like. It seems you have 4-byte sized fields. But you only read ONE byte for each field here.
You likely can just read into the structure instead. If you really want to have an intermediate buffer you have to properly calculate offsets as padding could have screwed you over. Google for offsetof and padding.

memset throwing segmentation fault

I am having some problem with writing a function to extract strings from a file as part of a bigger program. Everything seems to be working fine, except when I use memset or bzero to erase the character arrays I have been using. I have been sitting with this problem for more than an hour and I keep getting seg faults whatever I do. I am getting this error for both bzero and memset. Please help me out.
I am attaching my code below. The statement "Come out of addfront" is printed but none of the "Done with all bzero" statements are printing. I get a segmentation fault at that point. Thank you
void extractFileData(FILE *fp , char clientName[])
{
char tempFileName[50], tempFilePath[100], tempFileSize[50];
struct stat fileDetails;
while(fgets(tempFileName, sizeof(tempFileName), fp)!= NULL)
{
if((newLinePos = strchr(tempFileName, '\n')) != NULL)
{
*newLinePos = '\0';
}
strcat(tempFilePath, "SharedFiles/");
strcat(tempFilePath, tempFileName);
if(stat(tempFilePath, &fileDetails) < 0)
{
perror("Stat error");
exit(1);
}
//Copy it into a string
sprintf(tempFileSize, "%zu", fileDetails.st_size);
printf("temp file size: %s\n", tempFileSize);
//Add all these details to the file list by creating a new node
addFront(tempFileName, tempFileSize, clientName);
printf("Come out of addfront\n");
memset(&tempFileName, 0, 45);
printf("Done with all bzero\n");
memset(&tempFileSize, 0, sizeof(tempFileSize));
memset(&tempFilePath, 0, sizeof(tempFilePath));
printf("Done with all bzero\n");
}
}
EDIT:
void addFront(char fileName[], char fileSize[], char clientName[])
{
FILENODE* n;
printf("Inside add front function\n");
strcpy(n->fileName, fileName);
printf("n->filename: %s\n", n->fileName);
strcpy(n->fileSize, fileSize);
printf("n->filesize: %s\n", n->fileSize);
strcpy(n->ownerName, clientName);
printf("n->ownername: %s\n", n->ownerName);
myFileList.head = n;
printf("Did it go past myfilelist head = n\n");
myFileList.numOfNodes++;
printf("num of nodes: %d\n", myFileList.numOfNodes);
}
I have added my code for the addFront function. It basically adds
the details to a struct myFileList which is basically an implementation
of a linked list. The FILENODE represents each entry in the list.
EDIT:
Adding the structs I am using
struct fileNode
{
char fileName[50];
char fileSize[50];
char ownerName[25];
struct fileNode* next;
};
struct fileList
{
struct fileNode* head;
struct fileNode* tail;
int numOfNodes;
};
typedef struct fileList FILELIST;
typedef struct fileNode FILENODE;
I don't know why your program would crash there. But I can another error in the program. Fix the other error first, see if you still have problems.
This is wrong:
strcat(tempFilePath, "SharedFiles/");
strcat(tempFilePath, tempFileName);
The tempFilePath variable is uninitialized. This may coincidentally not crash, but you cannot rely on it not to crash. It may scribble on your stack.
Do this instead:
snprintf(tempFilePath, sizeof(tempFilePath), "SharedFiles/%s", tempFileName);
Finally, there is no need to zero the arrays. The contents of the arrays are not used in the next loop iteration, so you might as well ignore them.
void extractFileData(FILE *fp , char clientName[])
{
char tempFileName[50], tempFilePath[100], *newLinePos;
struct stat fileDetails;
while (fgets(tempFileName, sizeof(tempFileName), fp)) {
if ((newLinePos = strchr(tempFileName, '\n')))
*newLinePos = '\0';
snprintf(tempFilePath, sizeof(tempFilePath),
"SharedFiles/%s", tempFileName);
if (stat(tempFilePath, &fileDetails) < 0) {
perror("Stat error");
exit(1);
}
printf("temp file size: %zu\n", tempFileSize);
addFront(tempFileName, tempFileSize, clientName);
}
}
The snprintf() function is really the number one choice for doing work like this in C. It's easy to write code with snprintf() that "obviously won't crash", as opposed to code that "won't obviously crash".
If your code still crashes, there is an error somewhere else.
addFront() needs a n = malloc( sizeof *n) before you do anything with it.

Resources