This function is supposed to save data to a library.books_count instance of a dynamic array of pointers to structures. Yet it does not. A similar function addexistingBooks() does it flawlessly. What is the problem in realloc()?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char book_name[32];
char book_genre[32];
char author[32];
int page_count;
float price;
}Sbook;
typedef struct
{
char library_name[32];
Sbook * bookp;
int books_count;
}Slib;
void menu(char String[50]);
void addexistingBooks(Slib library, int i);
void addBook(Slib library, int i);
int main()
{
Slib library;
int i=0;
char Choice[30];
printf("Enter amount of books inside the library: ");
scanf("%d", &(library.books_count));
library.bookp = (Sbook *)calloc(library.books_count,sizeof (Sbook));
fflush(stdin);
addexistingBooks(library, i);
menu(Choice);
if(strcmp(Choice,"add")==0)
{
addBook(library, i);
}
free(library.bookp);
return 0;
}
void menu(char String[30])
{
printf("Welcome to the library. If you read about heresy, prepare to be purged \n");
printf("Please choose a command, by writing the appropriate command: \n");
printf("1. Write 'add' to add a book. \n");
printf("2. Write 'remove' to remove a book. \n");
printf("3. Write 'redact' to redact a book. \n");
printf("4. Write 'Sort by criteria' to sort the books, where criteria can stand for: 1.bookname, 2.author, 3.genre, 4.price. \n");
printf("Enter your command: ");
gets(String);
}
void addexistingBooks(Slib library, int i)
{
for(i=0;i<library.books_count;i++)
{
printf("Enter the name of the book: \n");
fgets(library.bookp[i].book_name,32,stdin);
printf("Enter the genre of the book: \n");
fgets(library.bookp[i].book_genre,32,stdin);
printf("Enter the author of the book: \n");
fgets(library.bookp[i].author,32,stdin);
printf("Enter the page count of the book: \n");
scanf("%d", &(library.bookp[i].page_count));
printf("Enter the price of the book: \n");
scanf("%f", &(library.bookp[i].price));
fflush(stdin);
}
}
void addBook(Slib library, int i)
{
(library.books_count)++;
realloc(library.bookp,library.books_count);
fflush(stdin);
if(library.bookp==NULL)
{
exit(1);
}
printf("Enter the name of the book: \n");
fgets(library.bookp[i].book_name,32,stdin);
printf("Enter the genre of the book: \n");
fgets(library.bookp[i].book_genre,32,stdin);
printf("Enter the author of the book: \n");
fgets(library.bookp[i].author,32,stdin);
printf("Enter the page count of the book: \n");
scanf("%d", &(library.bookp[i].page_count));
printf("Enter the price of the book: \n");
scanf("%f", &(library.bookp[i].price));
fflush(stdin);
}
Your code contains several mistakes.
Lets start from the "non-blocking" mistakes. Those that, even if they can be really critical and have to be corrected, are not the real cause of the crash you experience.
The flush of standard input, fflush(stdin); is something that is not defined by the standard, so using it leads to undefined behavior: in some environments it could work, in some other environment it could not work, and there can be environments (the worst ones) in which it seems to work but it is actually harmful. It is recommended to avoid it.
Function gets() is dangerous because it doesn't provide any control on the size of the string inserted by the user, and its use should be avoided.
The issues in the void addBook() function
You try increasing the available space using realloc:
void *realloc(void *ptr, size_t size);
It needs the original pointer and the new size. But you pass library.books_count that is just the number of books. Meaning that, if the library used to contain 4 books, you try to allocate 5 bytes only.
You instead need to allocate library.books_count * sizeof(Sbook) bytes.
Furthermore it returns a new pointer. You need to assign it to the book pointer:
library.bookp = realloc(library.bookp, library.books_count * sizeof(Sbook));
In main() you initialize a i variable, but you never update it, since you store the numbers of books directly in library.books_count.
Then you pass it to addexistingBooks(), and it is redundant because you could use library.books_count itself for the loop, as you actually do. You can use it as the loop variable, but you don't need to have that parameter. Just
void addexistingBooks(Slib library, )
{
int i; /* If your C version is C99 or later, you can declare it in the loop itself */
for(i=0;i<library.books_count;i++)
{
/* Omissis */
}
}
Finally you pass it to addBook(), and not only it is redundant (as you can simply store the new book at index library.books_count-1, but it is actively harmful because you are always updating index 0 (because the value of parameter i is 0).
Although it is possible to pass structures to functions as values, it is not recommended. The first reason is that you will overload the stack of the process (the whole struct will be allocated in the stack area, that is quite big in PC applications but quite limited in embedded systems). The second reason will give you functional problems.
In fact, parameters passed by value are copies of the variables passed to the function. This means that any change made on them will not be reflected to original structures. In your case, the update of library.bookp pointer will not be available outside the function, causing (1) the original structure pointing to an invalid memory address location (becoming a dangling pointer), (2) the leak of the newly allocated memory, that nobody will be able to free().
Pass structures by address, instead, using pointers to structures. addBook() function, considering the i parameter removal, would become as follows
void addBook(Slib *library)
{
int i = library->books_count;
(library->books_count)++;
library->bookp = realloc(library->bookp, library->books_count * sizeof(Sbook));
/* and so on... the value of 'i' is now library->books_count-1 */
}
/* Call from main */
int main()
{
Slib library;
/* Omissis */
menu(Choice);
if(strcmp(Choice,"add")==0)
{
addBook(&library, i);
}
free(library.bookp);
return 0;
}
The definition of realloc function,
void *realloc(void *ptr, size_t size);
So, your realloc function:
realloc(library.bookp,library.books_count);
should change to:
library.bookp = realloc(library.bookp,sizeof(Sbook)*library.books_count);
OT, i see in your menu function, you use gets. It's dangerous, you should use fgets from stdin in stead. See in this link Why is the gets function so dangerous that it should not be used?
Related
Wrote a program TroubleTicket which allows the user to create a trouble ticket with various parameters. Code is using struct ticket {} to store ticket data. Each a new_ticket is added to tkt_array. The code is rather lengthy so I posted the relevant files and the code snippet. This is not a school project but a personal interest in learning some C.
Anyhow, there are functions, create_ticket() and update_ticket() which use _strdup() to handle user inputs. It's my understanding that _strdup() uses malloc() and this requires call to free() the memory. My approach is to call free() at program exit with the assumption that this will release malloc()ed memory. This task is done by function free_tkt_arr().
The function create_ticket() uses _strdup() when setting name, problem, assigned_to and status pointers.
Function update_ticket() is also using _strdup() to update ticket name, problem, assigned_to and status.
Upon code exit, function free_tkt_arr() is called to release memory allocated by _strdup().
What I'd like to know if calling free_ticket() on system exit releases all memory that was allocated by calls to _strdup() in create_ticket() and update_ticket()?
struct ticket {
int priority;
int number;
char *name;
char *problem;
char *assigned_to;
char *status;
};
The function create_ticket() uses _strdup() when setting name, problem, assigned_to and status pointers:
struct ticket tkt_array[NUM_TICKETS];
void create_ticket() {
char *ptr;
struct ticket new_ticket;
printf("Enter your name: ");
new_ticket.name = _strdup(get_input(20));
printf("Enter problem description: ");
new_ticket.problem = _strdup(get_input(100));
printf("Assigned to: ");
new_ticket.assigned_to = _strdup(get_input(20));
//printf("Enter ticket status: ");
//using _strdup() in case status is updated using _strdup which requires call to free()
ptr = "new";
new_ticket.status = _strdup(ptr);
}
Function update_ticket() is also using _strdup() to update ticket name, problem, assigned_to and status.
void update_ticket() {
printf("Enter ticket number: ");
ptr = get_input(8);
sscanf_s(ptr, "%d", &ticket_num);
if (*ptr == '1') {
printf("Updating Status.\n");
printf("Enter Status update: ");
tmp_ticket2.status = _strdup(get_input(20));
} else
if (*ptr == '2') {
printf("Updating Problem description.\n");
printf("Enter Problem description update. ");
tmp_ticket2.problem = _strdup(get_input(100));
} else
if (*ptr == '3') {
printf("Updating Assigned to.\n");
printf("Enter Assigned to update. ");
tmp_ticket2.assigned_to = _strdup(get_input(20));
}
}
function free_tkt_array() is called when exiting code and should be
freeing memory allocated by prior calls to _strdup()
void free_tkt_arr() {
for (int i = 0; i <= tkt_count - 1; i++) {
free(tkt_array[i].assigned_to);
free(tkt_array[i].name);
free(tkt_array[i].problem);
free(tkt_array[i].status);
}
}
I thought about downloading and learning valgrind but maybe that's a bit over my head.
Whether you should free the string or not depends on what get_input() does. If get_input() returns a block of allocated memory, there is no need to call strdup().
Note also that you should use strdup() instead of _strdup():
_strdup() is a Microsoft specific function that probably implements the same semantics as POSIX standard function strdup().
strdup() is available on Unix systems, specified in POSIX. It will be part of the upcoming C2x version of the C Standard (at last).
if strdup() is not available on your system, you can either use a macro of define it this way:
#include <stdlib.h>
#include <string.h>
char *strdup(const char *s) {
size_t size = strlen(s) + 1;
char *p = malloc(size);
if (p) {
return memcpy(p, s, size);
} else {
return p;
}
}
You can free() the memory, but you have also to assing NULL to the pointers, if you are not releasing the memory associated to the struct (which seems to be the case). As you allocate in static global memory an array of structures, you will get all of them initialized to NULL, so no need to initialize pointers initially to check if they have been allocated. But that doesn't hold after a while, so you have better to memset(3) or bzero(3) your structures, once you don't use them. You don't show how do you distinguish a used record from an unused one, but if you are using a pointer field as a flag to mark it as unused, then you have to set it to NULL once you have released the ticket. Lacking to do that, makes your pointers to continue pointing to unallocated memory (possible assigned by malloc(3) to other means, and a disastrous thing for your program)
You know, free(ptr) cannot make the pointer ptr to change to NULL, as every parameter is passed by value in C. So, free(ptr);, followed by ptr = NULL; is a good bet.
BTW, having a Minimal, Reproducible Example would be fine to search for any other possible mistake.
I created a simple C program to display about a simple bank transaction on withdrawals and deposits. I created the variables using structure. But there is a problem in passing structure variables within functions as they are not passing the values from one function to another as well as to main function.
#include <stdio.h>
#include <stdlib.h>
typedef struct Details{
char name[100];
char day[100];
int openingbalance;
int amount;
int closingbalance;
}detail;
void InputDetails(detail customer){
printf("Enter Customer name: ");
scanf("%s",customer.name);
printf("Enter the date: ");
scanf("%s",customer.day);
printf("Enter opening balance: ");
scanf("%d",&customer.openingbalance);
}
void transaction(detail customerr, int money){
int selection;
printf("Opening balance = %d\n",customerr.openingbalance);
printf("Select the transaction\n1.Withdrawal\n2.Deposit\n");
scanf("%d",&selection);
switch(selection){
case 1:
if(money > customerr.openingbalance){
printf("No sufficient balance in the account to process the request\n");
customerr.closingbalance = customerr.openingbalance;
}
else
customerr.closingbalance = customerr.openingbalance - money;
break;
case 2:
customerr.closingbalance = customerr.openingbalance + money;
}
}
void main()
{
detail client;
int amount;
InputDetails(client);
printf("Enter the transaction amount: ");
scanf("%d",&amount);
transaction(client, amount);
FILE *file1;
file1 = fopen("Bank.txt","a+");
printf("Name\tDate\tOpening Balance\tAmount Processed\tClosing Balance\n");
printf("%s \t%s \t%d \t%d \t%d\n",client.name,client.day,client.openingbalance,amount,client.closingbalance);
fprintf(file1,"%s \t%s \t%d \t%d \t%d\n",client.name,client.day,client.openingbalance,amount,client.closingbalance);
fclose(file1);
}
In the output it displays a wrong amount rather the entered opening balance and all the other variables including name and date.
You're passing the struct by value, which creates a copy of it. Operations on the struct in the function don't affect the original variables.
Instead of doing that, you may want to pass a pointer to the variable to your functions.
To do that, you need to change your function signatures to use a pointer to detail:
void InputDetails(detail *customer)
void transaction(detail *customerr, int money)
Since you're using a pointer, you need to dereference it to access the actual data pointed to by the pointer.
For other variable types you'd use the * indirection unary operator to access the value, which you can also do with structs:
(*customerr).closingbalance = (*customerr).openingbalance - money;
This is ugly. Instead of having to do this, you can use the -> operator, which is just a prettier way of doing the above:
customerr->closingbalance = customerr->openingbalance - money;
In your functions, you'd need to replace every use of the . operator on customerr with ->.
Doing this will save both time and memory since you don't have to make a local copy of the struct, and your program can function correctly.
When you call your functions, you'd use the & unary operator to take obtain the address of the struct variable and pass that, instead of the entire struct itself:
InputDetails(&client);
transaction(&client, amount);
You have to pass an object of a structure by reference through using a pointer to the object if you want that the original object would be changed in the function.
For example the function InputDetails should be defined like
void InputDetails(detail *customer){
printf("Enter Customer name: ");
scanf("%s",customer->name);
printf("Enter the date: ");
scanf("%s",customer->day);
printf("Enter opening balance: ");
scanf("%d",&customer->openingbalance);
}
and called like
InputDetails(&client);
I'm writing the following program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "planes.h"
int main(void)
{
plane* planes=NULL;
int size=0;
readPlanes(&planes, &size);
free(planes);
planes=NULL;
return EXIT_SUCCESS;
}
void readPlanes(plane** planes, int* size)
{
char buffer[100]={'\0'};
int airplaneID, modeli;
float fuel;
char modelc;
int invent=0;
int rettest=0;
do{
printf("Enter the number of planes:\n");
fgets(buffer, 100, stdin);
rettest=sscanf(buffer, "%d", size);
if((*size)<=0)
{
printf("Invalid number of planes: enter a non negative number\n");
rettest=0;
}
}while(rettest!=1);
*planes=(plane*)calloc((*size), sizeof(plane*));
for(invent=0; invent<(*size); invent++)
{
planes[invent]=calloc(1, sizeof(plane));
do{
rettest=0;
printf("Enter the airplaneID:\n");
fgets(buffer, 100, stdin);
rettest=sscanf(buffer, "%d", &airplaneID);
if(airplaneID<0)
{
printf("Invalid airplaneID: enter a positive number\n");
rettest=0;
}
}while(rettest!=1);
planes[invent]->airplaneID=airplaneID;
do{
rettest=0;
printf("Enter the model:\n");
fgets(buffer, 100, stdin);
rettest=sscanf(buffer, "%c %d", &modelc, &modeli);
if(modeli<0 || modelc<'A' || modelc>'Z')
{
printf("Invalid model: enter an uppercase letter followed by a non negative number\n");
rettest=0;
}
}while(rettest!=2);
planes[invent]->planemodel.letter=modelc;
planes[invent]->planemodel.number=modeli;
do{
rettest=0;
printf("Enter the fuel:\n");
fgets(buffer, 100, stdin);
rettest=sscanf(buffer, "%f", &fuel);
if(fuel<0.0f)
{
printf("Invalid fuel: enter a non negative number\n");
rettest=0;
}
}while(rettest!=1);
planes[invent]->fuel=fuel;
}
}
The header file is:
#ifndef PLANES_H_INCLUDED
#define PLANES_H_INCLUDED
typedef struct
{
char letter;
int number;
}model;
typedef struct
{
int airplaneID;
model planemodel;
float fuel;
}plane;
void readPlanes(plane**, int*);
int lowestFuel(plane*, int);
void printID(plane*, int, char*);
#endif // PLANES_H_INCLUDED
Anyway, when I run the program with planes=1 the program runs with no problems. However if I try to run it with 2 or more planes, the following error occurs (at the end of the program, after the user entered all the parameters for all the planes):
stack smashing detected: /home/user/Documents/program/bin/Debug/program terminated
Aborted(core dumped)
I have no idea why this is occurring and where is my problem. Can someone help me?
Given planes declared as a plane **, this allocation is incorrect:
*planes=(plane*)calloc((*size), sizeof(plane*));
You are allocating memory to which a plane * will point; inasmuch as you are considering that memory as the storage for an array, the elements of the array (e.g. (*planes)[0]) must therefore be of type plane. You are not allocating enough space for a *size elements of type plane, however; only enough for that many pointers.
A good form to use for allocations specifies the wanted size in terms of the pointer to which the allocation is being assigned; for example,
mytype *p;
p = calloc(n, sizeof (*p));
Observe that the size of the allocation is defined in terms of the size of the thing to which p points, which is almost always what you want, without hard-coding p's type. That not only reduces the scope for errors, it is also flexible with respect to changes to p's type. (Note also that casting the result of malloc / calloc / realloc in C is not only unnecessary, but is regarded by many as poor form.)
In your case, the pointer for which you are allocating is *planes, so the above form would be realized as
*planes = calloc(*size, sizeof(**planes));
You seem to be confused by the double pointer, however. The only reason for it is to enable readPlanes() to modify its caller's local variable. It does not imply a requirement for multiple levels of allocation. In particular, having allocated memory and recorded a pointer to it in *planes, it makes no sense whatever to subsequently allocate more memory and assign it to planes[0], which is the same thing. It makes even less sense to attempt to assign anything to planes[1], however, because as this function was called, planes points to main's pointer planes, and therefore planes[1] points one plane* past that, to ... what? It's not defined, and your program therefore exhibits undefined behavior. That's your stack smashing.
In fact, you don't need the allocations in the loop at all -- you have already (after the first correction) allocated all the space you need. Because you assigned the pointer to *planes, you'll want to access it via that pointer; that means using expressions of the form (*planes)[n] to reference the nth plane. For example,
(*planes)[invent].airplaneID = airplaneID;
So the primary objective here is to take input from the user and store it in an array where each element in the array is a struct srecord. I would like to be able to retrieve the strings fname and lname as well as the score. This is crucial because I am going to also design other methods that will calculate the average of all students in the array and tell which students have the highest or lowest score.
For example in fill_in_srecord_array, if I wanted to print out the information in a[i] after running fill_in_srecord, would this be the proper line?
printf("%s %s: Score= %d\n", a[i].fname, a[i].lname, a[i].score);
But this does not compile, so what is wrong here?
Is my fill_in_srecord method working properly and actually filling in the array properly?
For future reference, what is the best way to access variables from a struct being stored in an array?
#include <stdio.h>
#include <string.h>
struct srecord {
char fname[20]; /* first name */
char lname[20]; /* last name */
int score;
};
void fill_in_srecord(struct srecord *r){
struct srecord new_student; //declare a new student record
r = &new_student; //assign a value to the pointer
printf("Enter student first name: "); //request input
scanf("%s", r->fname);
printf("First: %s",r->fname);
printf("\nEnter student last name: ");
scanf("%s", r->lname);
printf("Last: %s",r->lname);
printf("\nEnter student score: ");
scanf("%d", &(r->score));
printf("Score: %d\n", r->score);
}
void fill_in_srecord_array(struct srecord a[], int len){
a[len];
//struct srecord *p; //srecord pointer
for(int i = 0; i<len; i++) {
fill_in_srecord(&a[i]);
}
}
int main(){
struct srecord students[2];
fill_in_srecord_array(students, 2);
exit (0);
}
The problem here is that in the fill_in_srecord function you do
struct srecord new_student;
r = &new_student;
This is problematic for three reasons:
First is that new_student is a local variable, and it will go out of scope and disappear once the function returns. Any pointers to it will be stray pointers and using them will lead to undefined behavior.
The second problem actually makes the first problem moot, because when you pass a value to a function in C the values are copied and the function only gets a copy. Modifying a copy (like e.g. r = &new_student) will of course not modify the original.
The third problem is that when the function is called, you pass a pointer to a valid and existing instance of the srecord structure. There's simply no need for the new_student variable or the reassignment of r inside the function. Modifying r directly will be enough.
So the solution is simply to not have the two problematic lines.
There's another thing as well, the statement a[len]; that you have in the fill_in_srecord_array function it doesn't really do anything. But if it did anything it would lead to undefined behavior because you would index the array a out of bounds.
Right now you were making changes to local variable , which is not accessible out of function block and changes made to it are not done on the variable in calling function itself .
When you pass address of a[i] to function ,and if you make changes to that in function ,a[i] will be modified in the calling function itself . Because the changes will be made directly to content at its address , that is to itself .
What you need to do is write your function like this -
void fill_in_srecord(struct srecord *r){
/* struct srecord new_student; //declare a new student record */
/* r = &new_student; //assign a value to the pointer */
printf("Enter student first name: "); //request input
scanf("%s", r->fname);
printf("First: %s",r->fname);
printf("\nEnter student last name: ");
scanf("%s", r->lname);
printf("Last: %s",r->lname);
printf("\nEnter student score: ");
scanf("%d", &(r->score));
printf("Score: %d\n", r->score);
}
I just wrote this snippet of code and have passed values of integers in for when it scans the integer in, but am getting back the memory address of the int towards the end.. how do I display only the number that I just read in instead of it's address? Can I simplify this code snippet even more?
#include <stdlib.h>
#include <stdio.h>
typedef struct building {
char *blockName;
int blockNumber;
} building;
int main() {
building *blockA = (building*)malloc(sizeof(building));
building *blockB = (building*)malloc(sizeof(building));
blockA->blockName = (char*)malloc(25*sizeof(char*));
blockB->blockName = (char*)malloc(25*sizeof(char*));
blockA->blockNumber = (int)malloc(sizeof(int));
blockB->blockNumber = (int)malloc(sizeof(int));
printf("What is the name for your first block: ");
scanf("%s", (*blockA).blockName);
printf("What will be it's number: ");
scanf("%d", (*blockA).blockNumber);
printf("\n");
printf("What is the name for your second block: ");
scanf("%s", (*blockB).blockName);
printf("What will be it's number: ");
scanf("%d", (*blockB).blockNumber);
printf("\n");
printf("Your first block's name is %s. It's number is %d\n", (*blockA).blockName, (*blockA).blockNumber);
printf("Your second block's name is %s. It's number is %d\n", (*blockB).blockName, (*blockB).blockNumber);
printf("\n");
free(blockA->blockName);
free(blockB->blockName);
free(blockA);
free(blockB);
system("pause");
return 0;
}
The member
int blocknumber;
is a plain scalar integer, not a pointer. Use it directly, without allocating memory to it. This line:
blockA->blockNumber = (int)malloc(sizeof(int));
is very suspicious and your compiler should have warned you. (You do compile with warnings enabled, don't you?) You are tyring to store a pointer in an integer value, which will fail on machines where the size of a pointer is greater then the size of an int.
The remedy is not to allocate memory for a scalar, then
scanf("%d", &(*blockB).blockNumber);
(note the &), and then you will have the user input available as:
printf("It's number is %d\n", (*blockB).blockNumber);
On the other hand, the malloc for the string is right, because the string is an array of chars, in this case allocated on the heap and represented by a pointer to the first char.
Since building is defined as
typedef struct building {
char *blockName;
int blockNumber;
} building;
You shouldn't be doing this
blockA->blockNumber = (int)malloc(sizeof(int));
as the line building *blockA = (building*)malloc(sizeof(building)); will already have allocated space on the heap for the int blockNumber:
You can simply assign it
blockA->blockNumber = 1234;
Or prompt the user for it
scanf("%d", &(blockA->blockNumber));