I am new to C and I have been stuck on this code for the whole moring.
It compiles without a problem, but fails when executed.
If you have any idea that would help me solve this, please leave me a comment. Any comment would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct phonebook {
char name[20];
char phoneNum[20];
} Phonebook;
int bookSize=1;
void load(Phonebook **book);
void insert(Phonebook **book);
void delete(Phonebook **book);
void search(Phonebook *book);
void print(Phonebook *book);
void save(Phonebook *book);
int main(void) {
Phonebook *book = (Phonebook *)calloc(sizeof(Phonebook), bookSize);
load(&book);
int menuInput=0;
while(menuInput != 5) {
puts("***** MENU *****");
puts("1. Insert");
puts("2. Delete");
puts("3. Search");
puts("4. Print All");
puts("5. Exit");
printf(">> ");
scanf("%d", &menuInput);
switch(menuInput) {
case 1 : insert(&book); break;
case 2 : delete(&book); break;
case 3 : search(book); break;
case 4 : print(book); break;
case 5 : break;
default : puts("enter correct command"); break;
}
}
save(book);
free(book);
puts("\nexit\n");
return 0;
}
void load(Phonebook **book) {
FILE *fp = fopen("phonebook.txt", "rt");
if(fp == NULL) {
FILE *fp = fopen("phonebook.txt", "wt");
fclose(fp);
puts("Welcome! It looks like you don't have an existing phonebook.");
puts("A new phonebook has been created.\n");
return;
}
else {
char temp[20];
int i=0;
while(fscanf(fp, "%s", temp) != EOF) {
strcpy(book[i]->name, temp);
fscanf(fp, "%s", temp);
strcpy(book[i]->phoneNum, temp);
i++;
bookSize++;
*book = (Phonebook *)realloc(*book, sizeof(Phonebook) * (bookSize));
}
fclose(fp);
printf("Loaded %d contacts\n", bookSize-1);
}
}
void insert(Phonebook **book) {
puts("\nCreate a new contact");
getchar();
char temp[20];
printf("Name : ");
fgets(temp, 20, stdin);
//temp[strlen(temp)-1]=0;
strcpy(book[bookSize-1]->name, temp);
//fgets(book[bookSize-2]->name, 20, stdin);
//book[bookSize-2]->name[strlen(book[bookSize-2]->name)-1]=0;
printf("Phone : ");
fgets(temp, 20, stdin);
//temp[strlen(temp)-1]=0;
strcpy(book[bookSize-1]->phoneNum, temp);
//fgets(book[bookSize-2]->phoneNum, 20, stdin);
//book[bookSize-2]->phoneNum[strlen(book[bookSize-2]->phoneNum)-1]=0;
puts("Done!\n");
bookSize++;
*book = (Phonebook *)realloc(*book, sizeof(Phonebook) * bookSize);
}
void delete(Phonebook **book) {}
void search(Phonebook *book) {}
void print(Phonebook *book) {
if(bookSize == 1) {
puts("\nempty\n");
return;
}
puts("");
for(int i=0; i<bookSize-1; i++) {
printf("Name : %-10s Phone : %s\n", book[i].name, book[i].phoneNum);
}
puts("");
}
void save(Phonebook *book) {
FILE *fp = fopen("phonebook.txt", "wt");
for(int i=0; i<bookSize-1; i++) {
fprintf(fp, "%s\n%s\n", book[i].name, book[i].phoneNum);
}
fclose(fp);
printf("\nSaved %d contacts", bookSize-1);
}
Segmentation fault (core dumped)
** sorry for removing parts of the code I thought was 'irrelevant'! I have added the whole code to the post. Thanks!
As your other answer indicates, you are tripping over the details of the double indirection.
You are maintaining your phone book as an array of structures. In main, variable book is a pointer to the first structure in that array. The second will immediately follow it in memory, and the third will immediately follow that, etc.. That's all perfectly fine.
Both insert() and load() accept as a parameter a pointer to the pointer to the first book. This also is right and proper, because these methods reallocate the memory for the array. Reallocation is not necessarily done in place -- the new space may be in a different location than the old. The original pointer passed into realloc must be considered invalid after the call, and the return value used in its place (supposing the call succeeds). You handle this correctly, too, updating main's pointer through the pointer argument:
*book = (Phonebook *)realloc(*book, sizeof(Phonebook) * (bookSize));
But your attempts to write phone book entries into the allocated space is incorrect. For example, in load(), this:
strcpy(book[i]->name, temp);
tries to access the ith Phonebook * in the array of pointers to which book points, and to write to the name member of the Phonebook to which it points. But there is only ever one Phonebook *, not an array of them. You are allocating and reallocating space for the Phonebooks to which it points.
Here's a crude diagram:
Actual layout:
[Phonebook **] ----> [Phonebook *] ----> [ Phonebook, Phonebook, Phonebook ... ]
Being accessed as if it were:
[Phonebook **] ----> [Phonebook *, Phonebook *, Phonebook *, ...]
| | |
V | |
[Phonebook] V |
[Phonebook] V
[Phonebook]
Solution:
Just as you assign the allocated pointer to *book, not to book, it is *book to which you should be applying the indexing operator:
strcpy((*book)[i].name, temp);
And since it's an array of Phonebooks, not an array of pointers to them, you use the direct member access operator (.), as shown, not the indirect access operator.
Beware, however, that you use the same name, book, in different functions to designate pointers with different degrees of indirection. Thus, whereas the above would be correct in load() and insert(), it would be wrong in main() and some of the other functions.
tl;dr: insert(&book) should just be insert(book), and define this to be the address you get from allocating memory in the heap for storing the address you get from calloc.
You define your argument for insert() as **book, and when you get a *book from your calloc() call, you reasonably "add on another *" with the address operator &. The catch is that the address of *book that you got from your calloc call is a location on the call stack of your main() function. So, when the argument of strcpy() goes to dereference this address with the array index notation, it attempts to get the value located at the pointer that's on your call stack + bookSize - 1. This is already in undefined behavior territory, since the stack isn't supposed to store memory dynamically, but you're getting the segfault because the stack is at the top of the memory layout (high address area), so adding a large enough value to the dereferenced value of book puts you in an illegal memory access zone.
Related
I have created entry2_player helper function but I am looking for somebody that can verify if this is the correct responds to my given instructions below:
This expects a string entry, consisting of a name, space, and an int score.
When entry is "Sam 67", this function:
displays 'malloc() for "Sam 67" ...'
attempts malloc() for a Player:
if malloc() fails, the function displays: 'Failed! Returning NULL'
attempts to convert entry with *n = sscanf(...) to name and score of a
Player variable. If successful, (indicated by *n = 2) displays 'at address: 0x000....' and returns its address.
if entry is not valid, e.g. "Sam45", this function free the allocated memory,
and displays 'Invalid entry string! Returning NULL', and returns NULL.
REF: https://en.cppreference.com/w/c/io/fscanf
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
// Room for a short name string in Player:
#define NAME_SIZE 10
// Incremental number of memory, in units of pointers, by which to increase
// size of Player pointer array:
#define MALLOC_INCR 5
typedef struct {
char name[NAME_SIZE] ;
int score ;
} Player ;
Player * entry2_Player(char *entry, int *n) {
char name[10];
int score;
printf("\nmalloc() for %s ...", entry);
Player *pID = (Player *)malloc(sizeof(entry));
if (pID == NULL){
printf("Failed! Returning NULL");
return NULL;
}
*n = sscanf(entry, "%s %d", name, &score);
if (*n !=2){
printf("Invalid entry string!");
free(pID);
return NULL;
}
else{
printf("at address: 0x%p", &n);
return pID;
}
}
In my main function I am required to:
Create a single Player variable, using entry2_Player() with the string "Robin 78" and
display it with show_Player(). Store the Player in the array from part 2. Add a fifth Player
to the array directly from entry2_Player(). Display the Player array with show_Players()
I am looking to see if my return variables in entry2_player are correct in order for me to continue with this next instructions.
First, what you're actually doing:
You allocate a block of memory of size of pointer to char. On current systems, this could be 8 bytes. Then you're trying to read two items from the input string entry into the (locally - stack - allocated) variables name and score. If that succeeds, you're returning the 'untouched' allocated block of memory.
What you probably want to do:
Allocate a block of memory of size Player. Without knowing the system specs, sizeof(Player) > sizeof(char*). Then you want to read two items from the input string entry into the fields name and score of the allocated Player object. And if that succeeds, you'll return the 'properly initialized' Player object.
Btw.
printf("at address: 0x%p", &n);
What do you want to present here? n is a pointer, that means it contains the address of an int. The above statement prints the address of the pointer.
I think, the following was the intention:
printf("at address: %p", pID); //%p prints the address in hex format, preceded by '0x'
sizeof entry == sizeof(char*) will not return the length of the string entry, but the number of bytes required to store a pointer to char.
strlen(entry) will give you the length of the string entry.
Based on the comment below, here the formal explanation:
Player * entry2_Player(char *entry, int *n)
{
printf("\nmalloc() for %s ...", entry);
//alloc Player object
Player *pID = malloc(sizeof(Player));
if (pID == NULL){
printf("Failed! Returning NULL");
return NULL;
}
//parse entry into the fields of pID
*n = sscanf(entry, "%s %d", pID->name, &pID->score);
if (*n !=2){
printf("Invalid entry string!");
free(pID);
return NULL;
} else {
printf("at address: %p", pID); //address of allocated memory
return pID;
}
}
The part that is bothering me is the last for loop which I used just to test whether the data is entered correctly and that it is printed using printf properly. The three access methods used to print the data which I entered aren't quite clear to me.
In access method #1 I managed to print data properly using only one arrow operator to access name. The part I can't wrap my head around is why am I able to access the data without an error? I only used index to access each production_plant_employees structure. I know the brackets do the dereferencing, but I still don't understand what's happening there. I tried writing that part like this : *(production_plant_employees + i), but it didn't work.
Access method #2 is fully clear to me.
Now the access method #3, that's the one I assumed would work, but it refuses to. When written, IDE shows no errors, but when I run the program, it stops.
I am supposed to first access data in first pointer (which is production_plant_employees), and then then access data in second pointer (which is pointer basic_info which is in struct employee), and then, when I've gone through the 2 pointers, access the very data I am after (name, age, etc...), right?
Also, could you please show me any other possible ways of accessing the data I'm after?
typedef struct basicdata{
char name[15];
char last_name[15];
char gender[2];
int age;
char birthplace[15];
char address[15];
} BASICDATA;
typedef struct job_info {
int employment_year;
char job_position[20];
char employee_pay_grade[10];
int employee_grade;
} JOB_INFO;
typedef struct employee{
BASICDATA *basic_info;
JOB_INFO *job_info;
} EMPLOYEE;
int main () {
int i;
int choice = 0;
EMPLOYEE *production_plant_employees;
printf("Enter number of employees : \n");
scanf("%d", &choice);
production_plant_employees = (EMPLOYEE*)calloc(choice, sizeof(EMPLOYEE));
if (production_plant_employees == NULL) {
printf("An error occured during memory allocation\n");
}
for(i = 0; i < choice; ++i) {
production_plant_employees[i].basic_info = (BASICDATA*)calloc(choice, sizeof(BASICDATA));
if(production_plant_employees[i].basic_info == NULL) {
printf("An error occured during memory allocation\n");
}
production_plant_employees[i].job_info = (JOB_INFO*)calloc(choice, sizeof(JOB_INFO));
if(production_plant_employees[i].job_info == NULL) {
printf("An error occured during memory allocation\n");
}
printf("production_plant_employees[%d].basic_info = %d\t%x\n", i, production_plant_employees[i].basic_info, production_plant_employees[i].basic_info);
printf("production_plant_employees[%d].job_info = %d\t%x\n", i, production_plant_employees[i].job_info, production_plant_employees[i].job_info);
}
for(i = 0; i < choice; ++i) {
fflush(stdin);
printf("Enter name : \n");
fgets(production_plant_employees[i].basic_info->name, 15, stdin);
printf("Name of %d. employee : %s", i, production_plant_employees[i].basic_info->name) //access method#1
printf("Name of %d. employee : %s", i, (production_plant_employees + i)->basic_info->name); //access method #2
printf("Name of %d. employee : %s", i, *(*(production_plant_employees +i)).basic_info->name); //access method #3 ---> why isn't this working?
printf("\n\n");
}
return 0;
}
The right way to do it is (for access method 3):
printf("Name of %d. employee : %s", i, (*(*(production_plant_employees +i)).basic_info).name);
First we start by dereferencing pointer production_plant_employees +i, now, we access member basic_info which is also a pointer & needs to get dereferenced using the second * to access local member name.
ptr1 = production_plant_employees +i
ptr2 = (*ptr1).basic_info
data = (*ptr2).name
And thus (substituting ptr2 in data:
data = (*(*ptr1).basic_info).name
& finally by substituting ptr1 :
data = (*(*(production_plant_employees +i)).basic_info).name
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 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've a newbie question regarding freeing memory allocated for an array of struct.
This is the code:
typedef struct {
char code[6];
char name[31];
char cname[31];
int anno;
} cliente;
cliente *readcostumers(char*filename,int * dim) {
int i;
cliente *d;
cliente temp;
FILE*fp;
fp=fopen(filename,"r");
*dim=0;
//count the number of lines
while(fscanf(fp,"%s %s %s %d", temp.code, temp.name, temp.cname,&(temp.anno))==4)
(*dim)++;
rewind(fp);
//allocate "dim" struct
int ss = sizeof(cliente);
d = (cliente*)malloc(ss * (*dim));
cliente *currCli = d;
//assign lines to struct
for(i=0; i<*dim; i++) {
fscanf(fp,"%s %s %s %d",currCli->code, currCli->name, currCli->cname, &(currCli->anno));
currCli = currCli + ss;
}
fclose(fp);
return d;
}
This piece of code basically reads a text file, with any number of lines, formatted with a specific pattern and assign the contents to an array of strcut cliente.
This seems to work fine, except when i free the memory previous allocated:
int main () {
int x,i;
cliente *f = readcostumers("c:/temp/clienti.txt",&x);
int len = sizeof(cliente);
for(i=0; i<x; i++) {
printf("\n%s %s %s %d",(f + len*i)->code, (f + len*i)->name,
(f + len*i)->cname, (f + len*i)->anno);
}
free(f);
}
The last statement free(f) causes a SIGTRAP exception, altough the values printed are correct read from file.
The file content is this:
A3789 Paolo Rossi 2001
X478D Marcantonio Bianchi 2004
Where is the mistake?
When you increment currCli in readcostumers you should use 1 and in main you shouldn't multiply the index with len. These are taken care of by the language. These two errors are compensating each other, but in the mean time you are accessing outside the allocated memory and most likely overwriting internal administration of the heap allocation algorithms. Ultimately resulting in a crash in free.
Look into the valgrind tool as it finds these kind of errors flawlessly.
What are you doing here?
currCli = currCli + ss;
You should be incrementing the pointer by 1, not by the size of an element in the array you allocated. (The language automatically scales pointer additions by the size of the object pointed to.) This leads to writing outside the allocated area, which in turn leads to corrupted memory, and SIGTRAP or core dump or other similar problems.