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.
Related
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.
I am new here and I need some help. I want to learn how can I pass a NULL list to a function fill it and then returning it to my main function.
FOR INSTANCE:
#include <cstdio>
typedef struct empNode {
char amka[12];
char first_name[30];
char last_name[30];
int year; //etos proslhpshs
float salary;
int num_of_children;
Child *children;
struct empNode *next;
} empNode;
void load_employees_from_file(empNode **employees);
//===========================================================
int main(void) {
empNode *employees = NULL;
load_employees_from_file(&employees);
while (employees != NULL) {
printf("%s ", employees->amka);
employees = employees->next;
}
}
//===========================================================
void load_employees_from_file(empNode **employees) {
FILE * fp;
int num_of_employees;
int i;
fp = fopen("employees.txt", "r");
if (fp == NULL) {
printf("Something went wrong, try again.\n");
return;
}
// here we read the first line of file to see how employee we have
fscanf(fp, "%d ", &num_of_employees);
while (num_of_employees) {
*employees = (empNode*) malloc(sizeof (empNode));
fscanf(fp, "%s ", (*employees)->amka);
fscanf(fp, "%s ", (*employees)->first_name);
fscanf(fp, "%s ", (*employees)->last_name);
fscanf(fp, "%d ", &(*employees)->year);
fscanf(fp, "%f ", &(*employees)->salary);
fscanf(fp, "%d\n", &(*employees)->num_of_children);
if ((*employees)->num_of_children > 0) {
(*employees)->children = (Child*) malloc(((*employees)->num_of_children) * sizeof (Child));
for (i = 0; i < (*employees)->num_of_children; i++) {
fscanf(fp, "%s ", (*employees)->children[i].fname);
strcpy((*employees)->children[i].lname, (*employees)->last_name);
fscanf(fp, "%d\n", &(*employees)->children[i].year_of_birth);
}
}
(*employees)->next = (empNode*) malloc(sizeof (empNode));
*employees = (*employees)->next;
num_of_employees--;
}
fclose(fp);
}
I get an error when I am running the while in my main function, more specifically my program crashes.
-------------------------------------------------------------------
ok let mu put it more clearly, after corrections i dont have problem with my list in the function the problem is that my list cant transfer to my main function. A clear example of this this:
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int data;
struct node *next;
}node;
void read_int(node **nn);
int main(void)
{
node *nn=NULL;
read_int(&nn);
printf("%d", nn->data);
return 0;
}
void read_int(node **nn)
{
FILE *fp;
fp=fopen("test.txt", "r");
fscanf(fp, "%d", (*nn)->data);
fclose(fp);
}
here is exactly the same problem and more easier to understund, the test.txt files contains just the number 2. but i cant print it in my main.
In your function void load_employees_from_file(empNode **employees)
Change :
(*employees)->next = (empNode*) malloc(sizeof (empNode));
to
(*employees)->next = NULL;
as immediately after that *employees becomes next and the while loop starts from the beginning where memory is dynamically allocated:
*employees = (empNode*) malloc(sizeof (empNode));
and then populated.
Otherwise, if this was the last employee, the next element remains the NULL pointer.
In this way, your main's while loop termination condition will be true when the last next element (pointing to NULL) is reached.
Skimming through your code, there seems to be several problems. You should learn to use a debugger, which would let you step through the code line-by-line during execution and observe the actual behavior.
Here are some obvious issues I think you should look at:
What do you think the value of *employees will be when the while loop exits? Specifically, think about this statement: *employees = (*employees)->next;
I assume you want this list to be NULL-terminated (otherwise, the while (employees != NULL) in your main function wouldn't make sense). In that case, where do you set the NULL terminator value? You don't seem to ever set the next field to NULL anywhere...
Why do you call malloc twice in the body of your loop? You seem to be allocating two different blocks of memory to represent the same employee.
I think #1 above is the reason that your program is crashing right now. (But if you fix that issue, your program will probably still crash due to one of the other issues.)
Right now, on the last iteration of your loop, you do this:
(*employees)->next = (empNode*) malloc(sizeof (empNode));
*employees = (*employees)->next;
This means that *employees (which points to employees from main) will always end up pointing to an uninitialized empNode struct. Since the memory is uninitialized, the next pointer will be garbage. That's definitely going to cause some problems.
I have a text file:
In 0 John 66
In 1 May 77
In 0 Eliz 88
Out 0
Out 0
I'm trying to parse this text file using scanf, and at the moment send the values after "In" to the add function, however I'm getting a seg fault when trying to do this.
I have some code here:
A struct in a seperate header file:
typedef Officer test;
typedef struct {
test tests[6];
int s;
} copList;
And this one:
typedef struct {
char name[25];
int id;
} Officer;
Then I have my main method
int main(void) {
FILE * ptr;
char buffer [500];
char * temp;
int pos;
int grade;
char * name;
copList * L;
ptr = fopen("test.txt","r");
if(ptr == NULL)
exit(1);
temp = malloc(sizeof(char)*10);
name = malloc(sizeof(char)*10);
L = malloc(sizeof(copList));
while(fgets(buffer,500,ptr) != NULL) {
sscanf(buffer,"%s %d %s %d\n",temp,&pos,name,&grade);
add(L->tests[pos],pos,L); //this gives me a seg fault
}
free(name);
free(temp);
free(L);
fclose(ptr);
return 0;
}
In a separate c file I have the add function.(Can't be changed)
void add(Test b, int pos, copList * L) {
//code to be added here later...
}
I've tried allocating different amounts of memory, but that didn't help. Also I noticed if I set a value to pos, in the while loop, before the add function call, I don't get a seg fault, but obviously that's not what I want, because the value wouldn't change. Any help would be much appreciated.
The main problem I see with your code is that it does not check the return value of sscanf -- if sscanf returns something other than 2 or 4, that means your input is something other than what you say it is. In addition, the arrays temp and name might overflow (on inputs other than what you show), which would cause undefined behavior. Finally, the spaces and \n in the sscanf format are wrong and should be removed (though they shouldn't actually cause any problems in this case.)
So you code should be something like:
while(fgets(buffer,500,ptr) != NULL) {
int count = sscanf(buffer,"%9s%d%9s%d",temp,&pos,name,&grade);
if (count != 2 && count != 4) {
fprintf(stderr, "Invalid input line: %s", buffer);
continue; }
... do stuff with temp and pos (only use name and grade if count == 4)
in this line:
add(L->tests[pos],pos,L);
the first parameter is a copy of the 'test' struct.
It is almost always a bad idea to pass a whole struct. Much better to just pass a pointer to the struct:
add( &(L->tests[pos]), pos, L );
Then, this line has a couple of problems:
void add(Test b, int pos, copList * L) {
1) 'Test' is a non-existent type, perhaps you meant: 'test'
2) 'b' is expecting a passed struct. as mentioned above,
it is (almost) always better to pass a pointer to a struct.
I am currently working on creating a dictionary using a binary search tree-like structure we designed in class.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
struct entry
{
char* word;
unsigned int n; /* n is the number of times the word appears in the source. */
struct entry *left;
struct entry *right;
};
/*input_from_args: if no additional argument is given, return stdin. Else, open the text file and read it.*/
FILE*
input_from_args(int argc, const char *argv[]){
if(argc==1){
return stdin;
}else{
return fopen(argv[1],"r");
}
}
Below is the insert function that we also wrote in my class. Given the new word we are looking at, if it is
struct entry*
insert(struct entry *table, char* str)
{
if(table == NULL){
table = (struct entry *)malloc(sizeof(struct entry));
strcpy(table->word,str);
table -> n = 1;
table -> left = NULL;
table -> right = NULL;
}else if(strcmp(str, table->word) == 0){
table -> n = (table ->n)+1;
}else if(strcmp(str, table->word) <0){
table->left = insert(table->left, str);
}else if(strcmp(str, table->word) >0){
table ->right = insert(table->right, str);
}
return table;
}
Below is a print function which I wrote myself which is to print every word in table and N, the number of times it occurs.
void
print_table(struct entry *table){
if(table!=NULL){
print_table(table->left);
printf("%s ", table->word);
printf("%d \n", table->n);
print_table(table->right);
}
}
And finally, below is the main function.
int
main(int argc, const char *argv[])
{
FILE *src = input_from_args(argc, argv);
if(src == NULL){
fprintf(stderr, "%s: unable to open %s\n", argv[0], argv[1]);
exit(EXIT_FAILURE);
}
char str[1024];
struct entry *table;
int c;
while((fscanf(src, "%s", str))!= EOF){
table = insert(table, str);
}
print_table(table);
return 0;
}
I'm having some very odd behavior when I run this function. It seems to only be happening when I run it with longer input.
When I run it with this input(in a .txt file):
This is a test.
This is a test.
This is a test.
I get the following output:
This 3
a 3
is 3
test 3
This is what I should be getting. However, when I give it slightly longer input, such as:
Apple Apple
Blue Blue
Cat Cat
Dog Dog
Elder Elder
Funions Funions
Gosh Gosh
Hairy Hairy
I get the following output:
Appme 2
Blue 2
Cat 2
Dog 2
Elder 2
Funions 2
Gosi 2
Hairy 2
Which is clearly correct as far as the numbers go, but why is it changing some of the letters in my words? I gave it Apple, it returned Appme. I gave it Gosh, it gave me Gosi. What's going on with my code that I am missing?
This line in the insert function is very problematic:
strcpy(table->word,str);
It's problematic because you don't actually allocate memory for the string. That means that table->word is uninitialized and its value will be indeterminate, so the strcpy call will lead to undefined behavior.
The simple solution? Use strdup to duplicate the string:
table->word = strdup(str);
The strdup function is not actually in standard C, but just about all platforms have it.
In your insert function, you do not allocate/malloc() space for the word pointer you are trying to strcpy() to:
if(table == NULL){
table = (struct entry *)malloc(sizeof(struct entry));
strcpy(table->word,str);
table -> n = 1;
table -> left = NULL;
table -> right = NULL;
}
Usually this code would exit with a segmentation fault, because you are copying data to memory you don't own, but this is easy to fix:
table->word = malloc(strlen(str) + 1);
strcpy(table->word, str);
You'll want to allocate one extra byte above the string length, to allow for the null terminator.
You do not need or want to cast the result of malloc(). In other words, this is fine:
table = malloc(sizeof(struct entry));
Get into the habit of using free() on any pointers you have malloc()-ed, when you are done with them. Otherwise, you end up with a memory leak.
Also, compile with -Wall -Weverything flags to enable all warnings.
Note: If one absolutely must use strdup(), it is easy to write a custom function to do so:
char* my_very_own_strdup(const char* src)
{
char* dest = NULL;
if (!src)
return dest;
size_t src_len = strlen(src) + 1;
dest = malloc(src_len);
if (!dest) {
perror("Error: Could not allocate space for string copy\n");
exit(EXIT_FAILURE);
}
memcpy(dest, src, src_len);
return dest;
}
On the line strcpy(table->word,str); where is table->word allocated?
So It copies only 4 bytes to table->word because pointer size is 4-bytes in your machine. So Be careful, you must allocate table->word there,
I would use this one instead of that table->word = strdup(str);
So I have the following question:
I have this struct ListAut
struct ListAut{
char* biggestn;
int sizeof_biggestn;
int total_len;
struct node* avl;
};
Its typedef is as it follows:
typedef struct ListAut *IndexOfAuts;
IndexOfAuts *newIndexOfAuts()
{
int i;
IndexOfAuts *ioa = malloc(27 * sizeof(struct ListAut));
for (i = 0; i < 27; i++)
{
ioa[i]->biggestn = "";
ioa[i]->sizeof_biggestn = 0;
ioa[i]->total_len = 0;
ioa[i]->avl = NULL;
}
return ioa;
}
void insertName(IndexOfAuts * ioa, char *nome)
{
char *aux = malloc(sizeof(nome));
aux = trim(nome);
int index = getIndexOfLetter(aux);
if (nameLen(aux) > getSizeOfLongName(ioa[index]))
{
strcpy(ioa[index]->biggestn, aux);
ioa[index]->sizeof_biggestn = nameLen(aux);
}
ioa[index]->total_len += nameLen(aux);
insert(ioa[index]->avl, aux);
}
This is an important part of a module I need for a project, and on its main it's Seg Faulting. I suspect it's on the creation of an "object" newIndexOfAuts(),
The idea of this module is to have an array of 27 pointers to those structures, one to each letter and another to the special characters;
Now I'm just confused because it might be from the problem above or from a module loader I made:
void loadModules(char *filename, IndexOfAuts * ioa, StatTable st)
{
char *nameofile = malloc(20);
strcpy(nameofile, filename);
FILE *file = fopen(nameofile, "r");
if (file != NULL)
{
int counter, ano;
char *buff, *field, *auxil;
buff = malloc(1024);
field = malloc(200);
auxil = malloc(200);
while (fgets(buff, 1024, file))
{
counter = 0;
field = strtok(buff, ",");
printf("inserting 1st name\n");
insertName(ioa, field);
counter++;
while (!atoi(field))
{
if ((auxil = strtok(NULL, ",")) != NULL)
{
counter++;
field = auxil;
insertName(ioa, field);
}
}
ano = atoi(field);
incPub(st, ano, counter - 1);
}
fclose(file);
}
}
When i run this in main that has the following lines:
printf("Creating Stat Table");
StatTable st=newStatTable();\\This Line is correct, i checked it,i hope
printf("Creating index");
IndexOfAuts* ioa=newIndexOfAuts();
printf("Loading Modules");
loadModules(filename,ioa,st);
Those prints were for me to see where was the cause of the seg fault, but the last line printed was the "Creating Index".
There are several cases of undefined behavior and one memory leak (and a possible case of undefined behavior too):
You have this initialization ioa[i]->biggestn=""; It make the biggestn member point to a constant array of one character (the '\0' character). You then do strcpy(ioa[index]->biggestn,aux); which will write over a constant character, and then go outside of the array writing into unknown memory.
You have this: char* aux=malloc(sizeof(nome)); That allocates only 4 or 8 bytes, which the size of the pointer and not what the pointer points to. Use strlen to get the length of a string.
For the above allocation you also need to allocate a byte extra, as strlen only returns the length of the string without the terminator.
You have aux=trim(nome); This overwrites the pointer you just allocated, leading to a memory leak.
The above call might also lead to undefined behavior if you return a pointer to a local variable or array.
There are probably other problematic lines, these were just the ones I found on a quick glance.
And a general tip: Learn to use a debugger! The debugger is a programmers best tool next to the compiler. If you run your program in a debugger, the debugger will stop at the location of the crash, and let you examine (and also walk up) the function call stack, as well as let you examine values of variables.