Working With Stacks in C - c

After many hours of working on trying to debug this code myself I'm giving up an seeking help. I created a program that is designed to hold a "record", a struct, of my choice and show I know how to utilize/manipulate them in memory. In my code I made a car inventory that allows you to add, delete, and print out structs. My struct looks like the following:
struct car{
char *make;
char *model;
int year;
int mpg;
int mileage;
int cost;
};
I use a menu system of number that allows the user to choose what to do with the struct. Anyways here's where I'm having the issue:
I can add two struct and print them all out just fine. However if I add more than two structs than I run into a seg fault. I've already tried to run GDB on it and I get the following error:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a60a03 in _IO_vfprintf_internal (s=<optimized out>, format=<optimized out>,
ap=<optimized out>) at vfprintf.c:1661
1661 vfprintf.c: No such file or directory.
As for how I am taking in this data I have 6 scanf() functions that take in the 6 characteristics of the struct, store them to a temporary variable, malloc for each string, malloc a new car struct called newCar, and set each variable inside struct to its temporary variable. If it's the first car entry then carInventory is equal to newCar. When adding another car the same process occurs except a while loop moves along a new struct called newCarInventory and stores data from carInventory using memcpy(). Below is the actual code I'm using:
void addRecord(){
newCar = (struct car *) malloc(sizeof(struct car)); //Allocates memory for a car entry
int i;
int inventoryAmountTemp = inventoryAmount; //Grabs the global value and stores it to a local variable
//Local variables used to hold onto inputted values
char make[25];
char model[25];
int year;
int mpg;
int mileage;
int cost;
printf("\nMake: ");
scanf("%s", &make);
printf("\nModel: ");
scanf("%s", &model);
printf("\nYear: ");
scanf("%i", &year);
printf("\nMiles Per Gallon: ");
scanf("%i", &mpg);
printf("\nMileage: ");
scanf("%i", &mileage);
printf("\nCost: ");
scanf("%i", &cost);
newCar->make = (char *)malloc(strlen(make)+2); //Allocates memory for string
newCar->model = (char *)malloc(strlen(model)+2);
strcpy(newCar->make, make); //Coppies string into newCar
strcpy(newCar->model, model);
newCar->year = year;
newCar->mpg = mpg;
newCar->mileage = mileage;
newCar->cost = cost;
if(inventoryAmountTemp == 0){
carInventory = newCar;
}
else{
newCarInventory = (struct car *) malloc(inventoryAmountTemp * sizeof(struct car)); //Memory made for a new Car Inventory.
headPtr = carInventory;
headPtr2 = newCarInventory;
tailPtr = newCar;
i = 0;
while(i <= inventoryAmountTemp){
memcpy(&(newCarInventory->make), &(headPtr->make), sizeof(headPtr->make));
memcpy(&(newCarInventory->model), &(headPtr->model), sizeof(headPtr->model));
memcpy(&(newCarInventory->year), &(headPtr->year), sizeof(headPtr->year));
memcpy(&(newCarInventory->mpg), &(headPtr->mpg), sizeof(headPtr->mpg));
memcpy(&(newCarInventory->mileage), &(headPtr->mileage), sizeof(headPtr->mileage));
memcpy(&(newCarInventory->cost), &(headPtr->cost), sizeof(headPtr->cost));
i++;
if(i < inventoryAmountTemp && i != inventoryAmountTemp){
headPtr++;
newCarInventory++;
}
else if(i == inventoryAmountTemp){
headPtr = tailPtr;
newCarInventory++;
}
}
newCarInventory = headPtr2;
carInventory = newCarInventory;
}
inventoryAmountTemp += 1;
accessTemp += 1;
access = accessTemp;
inventoryAmount = inventoryAmountTemp;
}
I know the issue resides from this function because I had fprintf() statements (that I took out in this code) that would test each step. The ones that would fail were the ones inside the while loop the as the loop went around the second time, of the third car entry.
Any guidance would be really appreciated!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
struct car{
char *make;
char *model;
int year;
int mpg;
int mileage;
int cost;
};
int inventoryAmount=0;
struct car* CarList=0;
char *copyString(char *str){
char *buff=0;
if(str){
int l=strlen(str);
buff=malloc(l+1);
if(buff){
for(int i=0;i<=l;i++)
buff[i]=str[i];
}
}
return buff;
}
/*_______________________________________________________
*/
void propmt(const char *msg,const char*fmt,void *output){
printf("\n%s: ",msg);
scanf(fmt,output);
return;
}
/*_______________________________________________________
*/
void addRecord(void){
struct car *newCar ;
//Local variables used to hold onto inputted values
char make[25];
char model[25];
int year;
int mpg;
int mileage;
int cost;
if(CarList){
newCar= realloc(CarList,sizeof(struct car)*(inventoryAmount+1));
}else{
newCar= malloc(sizeof(struct car));
}
if(!newCar){
printf("Failed to allocate new car\n");
exit(1);
}
CarList=newCar;
newCar=&newCar[inventoryAmount];
inventoryAmount++;
propmt("Make","%s", &make);
propmt("Model","%s", &model);
propmt("Year","%i", &year);
propmt("Miles Per Gallon","%i", &mpg);
propmt("Mileage","%i", &mileage);
propmt("Cost","%i", &cost);
newCar->make=copyString( make); //Coppies string into newCar
newCar->model=copyString( model);
newCar->year = year;
newCar->mpg = mpg;
newCar->mileage = mileage;
newCar->cost = cost;
return;
}
/*_______________________________________________________
*/
void listCars(void){
int i;
if(!inventoryAmount){
printf("\nNo cars in inventory\n");
return;
}
for(i=0;i<inventoryAmount;i++){
printf("Make: %s\n" ,CarList[i].make);
printf("Model:%s\n" ,CarList[i].model);
printf("Year:%i\n" ,CarList[i].year);
printf("Miles Per Gallon:%i\n" ,CarList[i].mpg);
printf("Mileage:%i\n" ,CarList[i].mileage);
printf("Cost:%i\n" ,CarList[i].cost);
printf("======================================\n");
}
return;
}
void pause(void){
printf("Press a key to continue");
_getch();
printf("\n");
}
int main(void){
int q;
for(;;){
_clrscr();
printf(
"1 - List cars\n"
"2 - Add new car\n"
"0 - Exit program\n");
scanf("%i",&q);
switch(q){
case 1:
listCars();
pause();
break;
case 2:
addRecord();
pause();
break;
case 0:
return 0;
break;
}
}
return 0;
}
a good sample of using malloc and realloc

Try using backtrace in gdb to see where the segmentation fault originates

Related

How do i create multiple distinguishable members in a struct

I need to store multiple distinguishable members in a struct for a personal diary to show different records for each day. I want multiple members like e1 without writing it 365 times. I want a solution that works e1 on a loop or on an array.
struct add
{
char day[365];
char date[365];
char time[365];
char place[365];
char data[365];
};
int main()
{
int i=1;
struct add e1;
while(i!=0)
{
printf("Enter Day:");
gets(e1.day);
printf("Enter Date:");
gets(e1.date);
printf("Enter Time:");
gets(e1.time);
printf("Enter Place:");
gets(e1.place);
printf("Tell me about your day:");
gets(e1.data);
printf("\n\n\n");
printf("Day: %s\n",e1.day);
printf("Day: %s\n",e1.date);
printf("Day: %s\n",e1.time);
printf("Day: %s\n",e1.place);
printf("Day: %s\n\n\n",e1.data);
}
return 0;
}
I don't think its possible to create different variable with each loop, you can refer to this question for info. Instead of making different instances, make your struct in a way so that it stores data for all (365) days. Something like array of strings so that it stores for all days, currently even if you write something like char day[365] it creates separate day for each instance. make something like:
struct add
{
char day[NUMBER_OF_STRING][MAX_STRING_SIZE]; // syntax
// MAX_STRING_SIZE does not need to be 365, i just used it because you used that
// otherwise it does not make sense, date , time etc won't take more than 10 char
char date[365][365];
char time[365][365];
char place[365][365];
char data[365][365];
};
Now keep on adding to a single instance of struct add using for loop, this should be easy.
Also Better approach can be to create a array of struct add itself with your original struct code.
This example does what you want, and you can create as many instance of add as you want.
I limit your loop to run once and have tested that the code works with visual studio 2019:
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define DAY_SIZ 20
#define DATE_SIZ 40
#define TIME_SIZ 20
#define PLACE_SIZ 120
#define DATA_SIZ (BUFSIZ - 1)
struct add
{
char day[DAY_SIZ];
char date[DATE_SIZ];
char time[TIME_SIZ];
char place[PLACE_SIZ];
char data[DATA_SIZ];
};
struct add* create_add_struct() {
struct add* rec;
rec = (struct add*)malloc(sizeof(struct add));
return rec;
}
void destroy_add_struct(struct add* rec) {
free(rec);
}
void clear_add_struct(struct add* rec) {
memset(rec->day, 0, sizeof(rec->day));
memset(rec->date, 0, sizeof(rec->date));
memset(rec->time, 0, sizeof(rec->time));
memset(rec->place, 0, sizeof(rec->place));
memset(rec->data, 0, sizeof(rec->data));
}
void get_text_from_user(const char prompt[], char *txt, int siz) {
char buf[BUFSIZ];
printf("%s", prompt);
fgets(buf, BUFSIZ, stdin);
memcpy(txt, buf, siz);
}
void fill_add_struct(struct add* rec) {
printf("Do not enter any lines longer than %d\n\n", BUFSIZ);
get_text_from_user("Enter Day:", rec->day, sizeof(rec->day) - 1);
get_text_from_user("Enter Date:", rec->date, sizeof(rec->date) - 1);
get_text_from_user("Enter Time:", rec->time, sizeof(rec->time) - 1);
get_text_from_user("Enter Place:", rec->place, sizeof(rec->place) - 1);
get_text_from_user("Tell me about your day:", rec->data, sizeof(rec->data) - 1);
}
void print_add_struct(struct add* rec) {
printf("\n\n\n");
printf("Day : %s\n", rec->day);
printf("Date : %s\n", rec->date);
printf("Time : %s\n", rec->time);
printf("Place: %s\n", rec->place);
printf("Data : %s\n\n\n", rec->data);
}
int main()
{
// The number of times we want the loop to run
int i = 1;
// Collect data from the user and print it
while (i-- != 0)
{
// Allocate memory and initialize it
struct add* rec = create_add_struct();
clear_add_struct(rec);
// Get data from the user and print it
fill_add_struct(rec);
print_add_struct(rec);
// Release memory
destroy_add_struct(rec);
}
// Return success
return 0;
}
The reason I allocate your structure, is to make sure a stack-overflow does not occur, no pun intended.
If you want to create 365 add structs, you can create them like so:
struct add **records;
records = (struct add **) malloc(sizeof(struct add *) * 365);
for(int idx = 0; idx < 365; ++idx) {
records[idx] = create_add_struct();
clear_add_struct(records[idx]);
/* ... insert code ... */
}
/* ... insert code ... */
// Free memory
for(int idx = 0; idx < 365; ++idx) {
destroy_add_struct(records[idx]);
}
free(records);
I have not tested if the last piece of code compiles and works. Again I use malloc() and free() to avoid a stack-overflow.
typedef struct
{
time_t tm;
char *description;
}entry;
typedef struct day
{
time_t date;
size_t nentries;
struct day *next;
entry entries[];
}day;
and create linked list od days. Every day has array of diary entries.

C programming : Grouping multiple strings and searching for it using an Unique key

Let's say for example you are entering the personal information of a student and you create a unique ID number for each student. What I'm having problems with is grouping those strings, and storing them together, so that it can be accessed through the ID.
I tried using memory allocation, however, it did not work out.
I'm quite new to C, so I'm not exactly sure on what to do.
Here is what I used :
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct {
int LogID;
char firstname[20];
char lastname[20];
int mark;
char *subjects[100];
} student;
int reg(void);
int main(void) {
reg();
return 0;
}
//Registration function
int reg(void) {
int choice,shift,found,compare, nosub, y, sub, subcount;
char studentname[20];
FILE *fp;
FILE *fp2;
printf("Enter Student Details:\n\nStudent ID: ");
scanf("%d",&student.LogID);
printf("Name: ");
scanf("%s",student.firstname);
printf("Surname: ");
scanf("%s",student.lastname);
printf("How many subjects does the student take? ");
scanf("%d", &nosub);
//Opens a text file and prints the student's ID and firstname
fp2=fopen("subjects.txt","a+");
fprintf(fp2, "\n\n%d\t%s", student.LogID, student.firstname);
int i = 1;
size_t malloc_size = 100; //Allocating memory size to store subjects student is taking
for(i = 0; i < nosub; i++) {
student.subjects[i] = malloc(malloc_size * sizeof(char));
printf("Please enter the subject :\n(1)Mathematics\n(2)English\n(3) Social Studies\n(4)Science\n");
scanf("%d", &sub);
switch (sub) {
case (1) :
printf("Mathematics\n");
break;
case (2) :
printf("English\n");
break;
case (3) :
printf("Social Studies\n");
break;
case (4) :
printf("Science\n");
break;
}
}
for(i = 0; i < nosub; i++) { //Prints subjects to file, but it doesn't work...
fprintf(fp2,"%s\n", student.subjects[i]);
}
fclose(fp2);
free(student.subjects[i]);
student.subjects[i] = NULL;
fp=fopen("studentfile.txt","a+");
//Prints certain student Information into another file...
fprintf(fp,"\n%d\t%s\t%s\t",student.LogID,student.firstname,
student.lastname);
fclose(fp);
printf("Registration has been successful\n");
getchar();
return 0;
}
There were a number of issues I noticed and I'll address some of them, starting with the struct which I recommend defining like this:
struct studentpack {
int LogID;
char firstname[20];
char lastname[20];
int mark;
char *subjects[100];
};
And under your main function, you can define the student entry for filling.
struct studentpack student;
which will be used over and over again in your code, as you did in your example, for filling from the user input.
In the switch you really don't need any parenthesis around the case numbers.
In addition to the printf statement in each case, try something like this:
case 1:
printf("%s\n", "Mathematics");
sprintf(student.subjects + i, "%s", "Mathematics");
break;
which will fill the subjects area that you memory allocated just prior.
Finally, for grouping together the ID's I would suggest starting with something like this:
#define MAXGROUP 1000
struct studentpack *group = calloc(MAXGROUP, sizeof(struct studentpack));
int studentno = 0;
And then after you print your subjects to the file (test that it is working first due to the sprintf change) you would assign to the group like this:
if (studentno < MAXGROUP) {
memcpy(group+studentno, &student, sizeof(struct studentpack));
studentno++;
}
The above will store away the student. Next you will probably want to iterate through the group variable, accessing group[0].LogID, group[1].LogID, etc. (all the way up to a maximum of 1000) just to confirm that all your data is there in memory.
For example you could write a function that steps through looking for a particular LogID and then calls a show or display function containing printf statements to see all the values on screen.
you need an array of students
struct student{
int LogID;
char firstname[20];
char lastname[20];
int mark;
char *subjects[100];
};
struct student students[100];
you now have space for 100 students. They are students[0], students[1],...students[99]
Now you can do
int studno = 0;
While(something)
{
printf("\Enter Student Details:\n\nStudent ID: ");
scanf("%d",&(students[studno].LogID));
....
studno++;
}

Error when adding another record to dynamic memory database

My task is to initialize a struct in a header with some data. Then using pointers, add/remove data by malloc-ing bigger/smaller chunks and copying the data over.
Currently, my addRecord function doesn't work as it always seems to add the same crap (Part of record number 1):
Name =
Fire Number = attan (Seems to be part of Manhattan)
Street = ork (Seems to be part of New York)
City = cret (Seems to be part of Secret)
State = tan (Seems to be part of Manhattan)
What am I doing wrong?
My header:
#include <stdio.h>
#include <stdlib.h>
struct structPointer{
char name[51];
char fireNumber[11];
char street[26];
char city[26];
char state[26];
};
My c file:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "myData.h"
struct structInit *sP;
struct structInit *sSP;
int recordNumber = 0;
int numberOfAccesses = 0;
int main(void) {
sP = (struct structInit *) malloc(5 * sizeof(struct structInit));
sSP = sP;
memcpy(sP->name,"Adam Baum",51);
memcpy(sP->fireNumber,"N1234",11);
memcpy(sP->street,"Top Secret",26);
memcpy(sP->city,"Manhattan",26);
memcpy(sP->state,"New York",26);
sP++;
recordNumber++;
memcpy(sP->name,"Adam Zapel",51);
memcpy(sP->fireNumber,"S4321",11);
memcpy(sP->street,"Throat",26);
memcpy(sP->city,"Manhattan",26);
memcpy(sP->state,"New York",26);
sP++;
recordNumber++;
memcpy(sP->name,"Al Bino",51);
memcpy(sP->fireNumber,"W1234",11);
memcpy(sP->street,"White",26);
memcpy(sP->city,"Anchorage",26);
memcpy(sP->state,"Alaska",26);
sP++;
recordNumber++;
memcpy(sP->name,"Anne Teak",51);
memcpy(sP->fireNumber,"E4321",11);
memcpy(sP->street,"Oak",26);
memcpy(sP->city,"Woodville",26);
memcpy(sP->state,"Wisconsin",26);
sP++;
recordNumber++;
memcpy(sP->name,"Barb Dwyer",51);
memcpy(sP->fireNumber,"N1234",11);
memcpy(sP->street,"Keepout",26);
memcpy(sP->city,"Kilgore",26);
memcpy(sP->state,"Texas",26);
recordNumber++;
sP = sSP;
int sel;
while (1){
printf("MENU\n");
printf("=====\n");
printf("1. Print All Records\n");
printf("2. Print Number of Records\n");
printf("3. Print Size of Database\n");
printf("4. Add Record\n");
printf("5. Delete Record\n");
printf("6. Print Number of Accesses to Database\n");
printf("7. Exit\n");
printf("=====\n");
printf("Enter selection: ");
scanf("%d", &sel);
printf("\n");
switch(sel){
case 1:
numberOfAccesses++;
printAllRecords(sP);
break;
case 2:
numberOfAccesses++;
fprintf(stderr,"There are a Total of %d records.\n\n", recordNumber);
break;
case 3:
numberOfAccesses++;
printSizeOfDatabase(sP);
break;
case 4:
numberOfAccesses++;
sP = sSP;
addRecord(sP);
break;
case 5:
numberOfAccesses++;
deleteRecord(sP);
break;
case 6:
numberOfAccesses++;
fprintf(stderr,"The total number of Accesses is %d\n\n", numberOfAccesses);
break;
case 7:
exit(0);
default:
printf("Error: Input was not a valid selection.\n\n");
break;
}
}
return 0;
}
int printAllRecords(struct structInit *structPointer){
int i;
structPointer = sSP;
printf("All Records: \n");
for(i=1;i<=recordNumber;i++){
printf("Record Number: %d\n", i);
fprintf(stderr, "Name = \%s\n", structPointer-> name);
fprintf(stderr, "Fire Number = \%s\n", structPointer-> fireNumber);
fprintf(stderr, "Street = \%s\n", structPointer-> street);
fprintf(stderr, "City = \%s\n", structPointer-> city);
fprintf(stderr, "State = \%s\n\n", structPointer-> state);
structPointer++;
}
return 1;
}
int printSizeOfDatabase(struct structInit *structPointer) {
int size = 0;
int i;
for (i=1;i<=recordNumber;i++) {
size += sizeof(structPointer->name);
size += sizeof(structPointer->fireNumber);
size += sizeof(structPointer->street);
size += sizeof(structPointer->city);
size += sizeof(structPointer->state);
structPointer++;
}
fprintf(stderr, "The size of the database is %d bytes.\n\n", size);
return size;
}
int addRecord(struct structInit *structPointer){
char entryName;
char entryFireNumber;
char entryStreet;
char entryCity;
char entryState;
recordNumber++;
struct structInit *theStruct;
theStruct = (struct structInit *) malloc ((recordNumber+1) * sizeof(struct structInit));
int i;
for (i=1;i<recordNumber;i++){
memcpy(theStruct->name,structPointer->name,51);
memcpy(theStruct->fireNumber,structPointer->fireNumber,11);
memcpy(theStruct->street,structPointer->street,26);
memcpy(theStruct->city,structPointer->city,26);
memcpy(theStruct->state,structPointer->state,26);
/*if(i==recordNumber){
theStruct++;}
else{
theStruct++;
structPointer++;}*/
theStruct++;
structPointer++;
}
theStruct++;
printf("Enter the Name of the New Record: \n");
scanf("%s",&entryName);
memcpy(theStruct->name,&entryName,51);
printf("Enter the Fire Number of the New Record: \n");
scanf("%s",&entryFireNumber);
memcpy(theStruct->fireNumber,&entryFireNumber,11);
printf("Enter the Street of the New Record: \n");
scanf("%s",&entryStreet);
memcpy(theStruct->street,&entryStreet,26);
printf("Enter the City of the New Record: \n");
scanf("%s",&entryCity);
memcpy(theStruct->city,&entryCity,26);
printf("Enter the State of the New Record: \n");
scanf("%s",&entryState);
memcpy(theStruct->state,&entryState,26);
structPointer=theStruct;
printf("Record has been added.\n\n");
return 0;
}
int deleteRecord(struct structInit *structPointer){
struct structInit *anotherStruct;
anotherStruct = (struct structInit *) malloc ((recordNumber+1) * sizeof(struct structInit));
int i;
for(i=0;i<5;i++){
memcpy(anotherStruct->name,structPointer->name,51);
memcpy(anotherStruct->fireNumber,structPointer->fireNumber,11);
memcpy(anotherStruct->street,structPointer->street,26);
memcpy(anotherStruct->city,structPointer->city,26);
memcpy(anotherStruct->state,structPointer->state,26);
structPointer++;
}
structPointer=anotherStruct;
recordNumber--;
printf("Record has been deleted.\n\n");
return 0;
}
At a glance:
The %s format specifier for scanf specifies a pointer to the first element of an array of char.
You're passing a pointer to one char.
It's just bad luck that the program doesn't crash completely.
You want
char entryName[51];
/* ... */
printf("Enter the Name of the New Record: \n");
scanf("%s", entryName);
and similar for the rest of the inputs.
Replace memcpy with strncpy - you shouldn't copy anything from outside the source object.
If you use realloc you can get rid of the entire copying loop when you expand your table.
Assigning to a parameter doesn't modify the value of the variable whose value you passed in.
This is as true for pointers as it is for everything else.
If you want to modify a variable, pass a pointer to it:
int addRecord(struct structInit **structPointer)
{
/* ... */
*structPointer = theStruct;
/* ... */
}
You don't need to do a memberwise memcpy between structs - in fact you don't need memcpy at all, since assignment works:
struct structInit a = /* ... */;
struct structInit b = /* ... */;
a = b; /* OK */
You need to make up your mind about whether to use global variables or parameters.
In particular, printAllRecords disregards the value of its parameter completely.
deleteRecord assumes that there are five records in your table.
You can also replace printSizeOfDatabase with this:
int printSizeOfDatabase() {
int size = recordNumber * sizeof(struct structInit);
fprintf(stderr, "The size of the database is %d bytes.\n\n", size);
return size;
}
You could use realloc in the add function.
A typedef would make the program a lot easier to read.
Please add this line to the end of mydata.h
typedef struct structPointer structInit;
Then before main() it becomes
structInit *sP;
structInit *sSP;
Then printAllRecords become :
int printAllRecords(structInit *structPointer)
Then turn ON your debugger and READ the messages.

Adding records with pointers to arrays

I have to create a program which adds records to a simple phone book. The code is below, but it doesn't work - function ends and then it stucks on declaring struct record x and doesn't want to display my added record - the program breaks down. When I put this part of code on the end of the function (but instead of "struct record x = array[0];" I put "struct record x = (*array)[0]") it works - record is printed. So I guess the problem is something about pointers, but I'm struggling and I really couldn't find out what's wrong. I remember that few weeks ago I created a program which was very similar but it was adding a new record to an array of integers, with fixed values and it was working well, so maybe there's something with structures that I don't know about. Thanks for any help!
I know the program isn't done yet and I know that I didn't make any action for temp_array == NULL, it'll be done after I found out what's going on.
struct record {
char f_name[SIZE];
char name[SIZE];
long int phone;
};
int add_record(struct record** array, int n)
{
struct record* temp_array = malloc((n+1) * sizeof(struct record));
if (temp_array == NULL)
{
free(temp_array);
return -1;
}
int i;
for (i=0; i < n; i++)
{
temp_array[i] = (*array)[i];
}
struct record new_record;
printf("\nAplly data.");
printf("\nFirst name: "); /*fgets(new_record.f_name, SIZE, stdin);*/ scanf("%s", &new_record.f_name);
printf("Surname: "); /*fgets(new_record.name, SIZE, stdin);*/ scanf("%s", &new_record.name);
printf("Phone number: "); scanf("%d", &new_record.phone);
temp_array[n] = new_record;
free (*array);
*array = temp_array;
//struct record x = (*array)[0];
//puts(x.f_name); puts(x.name); printf("%d", x.phone);
return 0;
}
main()
{
struct record* array; int n = 0;
int choice;
printf("\n1. Add record\n2. Delete record\n3. Find record\n0. Exit\n\nChoose action: ");
scanf("%d", &choice);
switch(choice) {
case 0: printf("\nKsiazka zostala zamknieta.\n"); return;
case 1: add_record(&array, n); n++; break;
case 2: return;
case 3: return;
default: printf("Wrong choice.\n\n"); return;
}
struct record x = array[0];
puts(x.f_name); puts(x.name); printf("%d", x.phone);
}
struct record* array=NULL;, and use %ld for long int – BLUEPIXY

Invalid pointer in C

I apologize in advance, but this is kind of a long one.
In my program, I read in the student's information, but when I go to output it, it comes out scrambled, and then gets a pointer error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student{
char *firstName;
char *lastName;
char id[10];
char gender;
int age;
double gpa;
};
void main()
{
int n;
struct student *classroom;
printf("How many students?");
scanf("%d",&n);
classroom = (struct student*) malloc(n*sizeof(struct student));
if (classroom == NULL)
exit(1);
readStudentsInformation(classroom,n);
outputStudents(classroom,n);
printf("The average age is %.2f.\n",averageAge(classroom,n));
printf("The average GPA is %.2f.\n",averageGpa(classroom,n));
sortByLastName(classroom,n);
outputStudents(classroom,n);
sortByID(classroom,n);
outputStudents(classroom,n);
sortByAge(classroom,n);
}
void outputStudents(struct student classroom[], int size)
{
int i;
for (i = 0; i < size; i++)
{
printf("%15s",classroom[i].firstName);
printf("%15s:",classroom[i].lastName);
printf("%14s,",classroom[i].id);
printf("%3c",classroom[i].gender);
printf("%5d",classroom[i].age);
printf("%5.2f",classroom[i].gpa);
}
}
Input:
How many students?2
First Name?Thom
Last Name?Arron
ID?2
Gender?M
Age?26
GPA?3.9
First Name?Frank
Last Name?Roberts
ID?1
Gender?F
Age?24
GPA?3.4'
Output:
Roberts Roberts: 2, M 26 3.90 : 1, F 24 3.40The average age is 25.00.
The average GPA is 3.65.
* glibc detected * ./lab12: munmap_chunk(): invalid pointer: 0x00007fff30319a90 *
: 2, M 26 3.90Aborted (core dumped)
The full code is here, but I didn't want to copy 200 lines to stack overflow: http://codepad.org/LYpS6t5z
Any idea what would cause this?
This is one conceptual error, you have it in a couple of places
classroom[i].firstName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
if (classroom[i].firstName == NULL)
exit(1);
classroom[i].firstName = temp;
What you want here instead is
classroom[i].firstName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
if (classroom[i].firstName == NULL)
exit(1);
strcpy(classroom[i].firstName, temp); // note this
Or, cleaned up a bit:
classroom[i].firstName = malloc(1+strlen(temp)); // note clean up here
if (classroom[i].firstName == NULL)
exit(1);
strcpy(classroom[i].firstName, temp);
Or even just
classroom[i].firstName = strdup(temp); // this takes place of all the lines above
These errors explain why your free's are failing.
Nothing else jumps out at me.
classroom[i].firstName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
if (classroom[i].firstName == NULL)
exit(1);
classroom[i].firstName = temp;
Your second assignment here overwrites the address, leaking the mallocd memory and making the pointer invalid as soon as that for iteration finishes. The same buffer is reused (with the same error) for lastName, which is why you see Roberts Roberts instead of the actual first and last name. When you go to free them, they are (1) invalid and (2) not made by malloc, so you get the crash you see.
Just like other arrays, you can't copy them by assignment, you have to copy byte-by-byte:
size_t len = strlen(temp);
classroom[i].firstName = malloc(1+len);
if (classroom[i].firstName == NULL)
exit(1);
strncpy(classroom[i].firstname, temp, len);
classroom[i].firstname[len] = '\0';
And don't cast the result of malloc.
Weirdness happening in readStudentsInformation, in particular lines like
classroom[i].lastName = temp;
are causing issues later on when you try to free this memory with
free(classroom[i].firstName);
Appropriate memory handling below:
void readStudentsInformation(struct student classroom[], int size)
{
int i;
char temp[50];
for (i = 0; i < size; i++)
{
printf("First Name?");
scanf("%s",temp);
classroom[i].firstName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
if (classroom[i].firstName == NULL)
exit(1);
/* after mallocing good memory can write in the data.. */
strcpy(classroom[i].firstName, temp);
/* classroom[i].firstName = temp; */
printf("Last Name?");
scanf("%s",temp);
classroom[i].lastName = (char*)malloc(sizeof(char)*(1+strlen(temp)));
if (classroom[i].lastName == NULL)
exit(1);
/* classroom[i].lastName = temp; */
strcpy(classroom[i].lastName, temp);
printf("ID?");
scanf("%s",classroom[i].id);
fflush(stdin);
__fpurge(stdin);
printf("Gender?");
scanf("%c",&classroom[i].gender);
printf("Age?");
scanf("%d",&classroom[i].age);
printf("GPA?");
scanf("%lf",&classroom[i].gpa);
}
}

Resources