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.
Related
I have a problem (or maybe a few)
I'm trying to struggle with pointers to pointers to struct, and I'm not understanding whether is a problem of memory allocation, or a problem of passing the right things to my function.
Here's (part of) the code
typedef struct Corsa {
char codice[15];
char partenza[15];
char destinazione[15];
int giorno, mese, anno, oraP, minP, oraA, minA, ritardo;
} corsa;
corsa** allocaStructArray(int numStruct);
void leggiEStampaStruct(FILE *fp, corsa **pntToCorsa, int numR);
// ..main and other functs..
corsa** allocaStructArray(int numStruct) //numStruct is the number of 'rows'
{
corsa **pointerToStructCorsa;
pointerToStructCorsa = malloc(numStruct * sizeof(corsa));
if (pointerToStructCorsa == NULL)
printf("\nErrore di allocazione.\n");
return pointerToStructCorsa;
}
void leggiEStampaStruct(FILE *fp, corsa **pntToCorsa, int numR) {
int i;
fclose(fp);
fp = fopen("file.txt", "r");
if (fp == NULL)
exit(232);
for (i = 0; i < numR; i++) {
fscanf(fp, "%s %s %s %d/%d/%d %d.%d %d.%d %d", pntToCorsa[i]->codice,
pntToCorsa[i]->partenza, pntToCorsa[i]->destinazione,
&pntToCorsa[i]->giorno, &pntToCorsa[i]->mese, &pntToCorsa[i]->anno,
&pntToCorsa[i]->oraP, &pntToCorsa[i]->minP, &pntToCorsa[i]->oraA,
&pntToCorsa[i]->minA, &pntToCorsa[i]->ritardo);
}
for (i = 0; i < numR; i++) {
printf("\n%s %s %s %d/%d/%d %d.%d %d.%d %d\n", pntToCorsa[i]->codice,
pntToCorsa[i]->partenza, pntToCorsa[i]->destinazione,
pntToCorsa[i]->giorno, pntToCorsa[i]->mese, pntToCorsa[i]->anno,
pntToCorsa[i]->oraP, pntToCorsa[i]->minP, pntToCorsa[i]->oraA,
pntToCorsa[i]->minA, pntToCorsa[i]->ritardo);
}
return;
}
Another thing that I don't like is that I can't check manually if everything is at its place.
Like if it was a normal matrix, I could have checked if the values were placed in the right spots but with pointers I literally can't and that doesn't help finding the problem.
Do you guys have some tips on this other problem?
At least these problems
No width in fscanf()
Do not use "%s" without a width limit in fscanf(). Use "%14s %14s %14s ... as each points to an array of 15.
Check input result
Check the return value. Add a test to see if the 11 specifiers all parsed.
if (fscanf(....) != 11) Handle_Error();
Allocation error
Wrong type in sizeof.
Avoid this problem by sizing to the refenced object and not the type. Easier to code right, review and maintain. Also, unclear what OP wants to do when numStruct < 0, so added a test.
// Wrong size v-----------v
// pointerToStructCorsa = malloc(numStruct * sizeof(corsa));
if (numStruct >= 0) {
// v--------------------------v Right size for referenced object.
pointerToStructCorsa = malloc(sizeof *pointerToStructCorsa * numStruct);
...
Im making a database, where the information about books and readers in a library are contained in two linked lists, and each line of the txt file contains the data of one book/peopleinlibrary.
Data of the books:
id;year;title;writer;isborrowed;\n
...
The id and the isborrowed(1or0) are integers, the rest are strings.
I know the atoi can convert the input lines to numbers, but when I use it while separating each line by commas, it just doesn't work, the printig is wrong and also i can't return with the *start/*begin pointer, where the list starts. By now im totally clueless because it's not the first method that I tried.
The part of the code:
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <stdlib.h>
typedef struct Konyv{
int id;
char *year;
char *title;
char *writer;
int ki;
struct Konyv*next;
}Konyv;
int main(){
Konyv*start=NULL;
FILE*f;
const char s[1] = ";";
int i;
f=fopen("konyv.adat.txt","r+");
Konyv*u;
if(f != NULL){
char line[1000];
while(fgets(line, sizeof line, f) !=NULL){
u= (Konyv*)malloc(sizeof(Konyv));
u->id = strtok(line, s);
u->id=atoi(u->id);
printf("%d ",u->id);
u->year = strtok(NULL,s);
printf("%s ",u->year);
u->title = strtok(NULL,s);
printf("%s ",u->title);
u->writer = strtok(NULL,s);
printf("%s ",u->writer);
u->ki = strtok(NULL,s);
u->ki=atoi(u->ki);
printf("%d",u->ki);
printf("\n");
u->next=NULL;
if(start==NULL){
start=u;
}
else{
Konyv *mozgo = start;
while (mozgo->next!= NULL){
mozgo = mozgo->next;
}
mozgo->next= u;
}
}
else{
printf("Error while opening.\n");
return 0;
}
printf("\n");
//test if start pointer is right by printig the list again(HELP)
Konyv* temp;
temp=start;
while(temp!=NULL) {
printf("%d ",temp->id);
printf("%s ",temp->year);
printf("%s ",temp->title);
printf("%s ",temp->writer);
printf("%d ",temp->ki);
printf("\n");
temp = temp->next;
}
free(u);
fclose(f);
return 0;
}
#WhozCraig is correct, and borrowing from this post you can see that we simply need to copy the data at the pointer to a new chunk of memory. For this we can use the strdup function included in string.h.
For example:
u->year = strtok(NULL,s);
becomes
u->year = strdup(strtok(NULL,s));
You can find documentation on strdup here for further reference.
Also, I don't want to leave you hanging here, the code you handed over didn't compile cleanly -- I had to complete some brackets.
One final thing storing anything other than an int in your id field is problematic. So,
u->id = strtok(line, s);
is an issue. Simple fix is,
u->id = atoi(strdup(strtok(line, s)));
but that is kind of dirty and hard to read for another programmer coming in to maintain code. I would advise taking the time to declare a variable just to temporarily store the token you are eventually going to duplicate into your struct.
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);
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 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.