How to implement dynamic arrays in C? - c

I am writing this code using dynamic memory allocation, for student records as indicated, this code suppose to be simple , I am obviously allocating elements in their correct places the right way, but when it comes to printing them, it gives me a "core dumped" error ! what is wrong ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main()
{
char **firstname;
char **lastname;
float *score;
int number_of_records,i,j,ctr=1,row=15,col=20;
/*ctr is to keep track of the student's number (makes it easier to
the user), it starts with (1)*/
firstname=malloc(row*sizeof(char*));
for(i=0;i<row;i++)
{
firstname[i]=malloc((col+1)*sizeof(char));
}
lastname=malloc(row*sizeof(char*));
for(i=0;i<row;i++)
{
lastname[i]=malloc((col+1)*sizeof(char));
}
printf("\nPlease indicate number of records you want to enter (min 2, max 15): ");
scanf("%d",&number_of_records);
score=malloc(row*sizeof(float));
printf("\nPlease input records of students\n(enter a new line after"
"each record), with following format:\nfirst name last name score ");
for (i=0;i<number_of_records;i++)
{
printf("\nEnter record for student %d : ",ctr);
scanf("%s %s %f",firstname[i],lastname[i],score[i]);
ctr++; /*ctr is to keep track of student number
(makes it easy to the user) */
}
for (i=0;i<number_of_records;i++)
{
printf("%s %s %f\n",firstname[i],lastname[i],score[i]);
}
}

Please change this:
for (i=0;i<number_of_records;i++)
{
printf("\nEnter record for student %d : ",ctr);
scanf("%s %s %f",&firstname[i],&lastname[i],&score[i]);
ctr++; /*ctr is to keep track of student number (makes it easy to the user) */
}
to this
for (i=0;i<number_of_records;i++)
{
printf("\nEnter record for student %d : ",ctr);
scanf("%s %s %f",firstname[i],lastname[i],&score[i]);
ctr++; /*ctr is to keep track of student number (makes it easy to the user) */
}
And it will work. The reason is that firstname[i] and lastname[i] are already pointers; you do not need to use & operator for them.
P.S. Also, since you are using C, do no cast the returning values from malloc or realloc. It will be done automatically.

Related

I'm new to C and am stuck with many issues, I have fixed them but I wonder if there are better ways

I'm new to C just coming out of my second university class that explained structs and string functions. I tried running the code we had written in the lesson and ban, one segmentation error, "gets" suddenly is banned by my compiler and I have spent the last couple of hours trying to make it work with rubber band solutions of bread-crumbs I found online.
As luck would have it I made it work, yet I would like to learn more: better solutions, other options, etc. I really would like a little guidance even if just to resources.
It's a simple code that ask for an int, then a string and a float, and loops around until the int is 0.
A problem that I couldn't fix is how to remove the new line "fgets" adds to get the style that I put the output in class, I don't know if I ask Google the wrong answer or if it isn't ask much because it is to obvious.
And before the recommendations of leaving the university come up, I'll ask the teacher about this, and hopefully he will give a good reason why he taught us like this.
Class code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CLEAR system("cls||clear")
typedef struct a
{
int id;
char *name;
float avarage;
} student;
int main()
{
student stud;
printf("\n Input ID: ");
scanf("%d", &stud.id);
while (stud.id != 0)
{
fflush(stdin);
printf("\n input the name: ");
gets(stud.name);
fflush(stdin);
printf("\n input the avarage: ");
scanf("%f", &stud.avarage);
CLEAR;
printf ("\n ID: %d | Name: %s | Avarage: %.2f", stud.id, stud.name, stud.avarage);
printf("\n\n Input ID: ");
scanf("%d" , &stud.id);
}
CLEAR;
return 0;
}
First I found fgets I put it in and it struck me with a segmentation error, Google what that was, then I used malloc to allocate memory space to the stud.name pointer, then it didn't blow up but i couldn't type anything in stud.name, spent 1 hour searching why, until I discover that it is because of the input buffer that is storing a new line from the first scanf (and the last by proxy) and that is what the fgets is reading, tried fflush(stdin): doesn't work, and then I find that getchar() stores this new line and it let me finally write in stud.name. Then, it finally worked.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CLEAR system("cls||clear")
typedef struct a
{
int id;
char *name;
float avarage;
} student;
int main()
{
student stud;
stud.name = (char *) malloc(sizeof(char) * 30);
printf("\n Input ID: ");
scanf("%d", &stud.id);
getchar();
while (stud.id != 0)
{
printf("\n input the name: ");
fgets(stud.name, 30, stdin);
printf("\n input the avarage: ");
scanf("%f", &stud.avarage);
getchar();
CLEAR;
printf ("\n ID: %d | Name: %s | Avarage: %.2f", stud.id, stud.name, stud.avarage);
printf("\n\n Input ID: ");
scanf("%d" , &stud.id);
getchar();
}
CLEAR;
return 0;
}

User Input to Array of Structs C

I am creating a program that gets user input and puts it into a struct called Student before returning back to a main menu. From the main menu you can add another student. This works but when I try to print all of the Students data that has been added to the array of structs it only prints the last Student that was added.
Here is the struct:
struct Student
{
char* firstName;
int age, cuid;
float GPA;
};
This is how I'm allocating space for the array in main:
struct Student* studentArray = malloc(*recordMaxPtr * sizeof(struct Student));
Here are the functions that capture user input and print the array:
// Gets info and adds student to the array of structs
void addStudents(struct Student* s, int *numStudents)
{
// Allocate memory for the first name
char *firstName = (char*) malloc(25*sizeof(char));
// Gets the name of student
printf("What is the name of the student you'd like to add? ");
gets(s->firstName);
printf("\n"); // blank line
// Gets age of student
printf("How old is the student? ");
scanf("%d", &s->age);
printf("\n"); // blank line
// Gets CUID
printf("What is his / her CUID number? ");
scanf("%d", &s->cuid);
printf("\n"); // blank line
// Gets GPA
printf("What is the student's GPA? ");
scanf("%f", &s->GPA);
printf("\n"); // blank line
}
// Sorts the array and then lists all of the saved students
void printStudents(struct Student* s, int *numStudents)
{
//bsort();
for (int i = 0; i < *numStudents; i++)
{
printf("Student #%d\n", i + 1);
printf(" Student's Name: %s\n", s[i].firstName);
printf(" Age: %d\n", s[i].age);
printf(" CUID: %d\n", s[i].cuid);
printf(" GPA: %2f\n", s[i].GPA);
}
}
I thought about trying to use a for loop to gather all of the student's data that I need at once but this is a school project and I'm not allowed to do it that way. I've been trying to figure this out for a while and I've sort of hit a brick wall on what to do. My best guess is that data is getting overwritten every time you enter a new student to the array but I'm not sure how to fix that.
You allocated a memory for the first name, but didn't save that anywhere. You have to store the address to the structure.
// Allocate memory for the first name
char *firstName = (char*) malloc(25*sizeof(char));
s->firstName = firstName; // add this
Also here are some more things to do for better code:
Check if malloc() succeeded
Check if scanf() succeeded
Replace gets() with fgets() and removal of newline character (gets() has unavoidable risk of buffer overrun and removed from new C specification)
Remove the cast of result of malloc() (c - Do I cast the result of malloc? - Stack Overflow)

Find Biggest Number in C, by N number of inputs

So I have this code:
#include <stdio.h>
int main()
{
char peopleName[5][20],peopleAge[5];
int i;
int maxAge=0, maxName=-1;
for(i=0;i<5;i++)
{
printf("Name & Age %d :",i+1);
scanf("%s",&peopleName[i]);
scanf("%d",&peopleAge[i]);
if(peopleAge[i]>maxAge)
{
maxAge=peopleAge[i];
maxName=i;
}
}
printf("%s %d", peopleName[maxName],peopleAge[maxAge]);
}
This code finds from 5 people the oldest one. I want to change from 5 people to N number of people, whatever the number I input myself. (For example I put 7, and I can insert seven names and ages and so on).
The question has two parts: How does the user specify how many persons are entered? And how do I store the data?
The second part is easy: No matter how many persons you are going to consider, if you just want to know who is the oldest, it is enough to keep the name and age of the currently oldest person. (Of course, if there is a tie and many people are, say, 80 years old, you just get to keep the first match.)
Not storing anything also simplifies the first question. You could ask the user to specify the number of persons beforehand and that's find if you have few people. If you have a list of many people, the user would have to count the by hand and then enter the count. Miscounting is very likely.
A better way is to indicate the end of input by another means, for example by a negative age or by two dashes as name. There is also the possibility that the input runs out, for example when redirecting input from a file or when pressing one of Ctrl-Z or Ctrl-D, depending on your platform, after the input.
The example below read the input line-wise and then scans that line. The loop while (1) is in theory infinite, in practice execution breaks out of the loop when the input runs out – fgets return NULL –, when a blank line is read or when the input isn't in the format single-word name and age.
#include <stdio.h>
int main(void)
{
char oldest[80] = "no-one";
int max_age = -1;
int count = 0;
puts("Enter name & age on each line, blank line to stop:");
while (1) {
char line[80];
char name[80];
int age;
if (fgets(line, sizeof(line), stdin) == NULL) break;
if (sscanf(line, "%s %d", name, &age) < 2) break;
if (age > max_age) {
strcpy(oldest, name);
max_age = age;
}
count++;
}
printf("The oldest of these %d people is %s, aged %d.\n",
count, oldest, max_age);
return 0;
}
You can do this -
int n; // number of people
scanf("%d",&n); // take input from user
char peopleName[n][20],peopleAge[n]; // declare 2-d array
for(i=0;i<n;i++)
{
// your code
}
Also this statement -
scanf("%s",&peopleName[i]); // pass char * as argument to %s
should be -
scanf("%19s",peopleName[i]); // one space is left for null character
You can use malloc to allocate buffer dynamically.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char (*peopleName)[20];
int *peopleAge;
int i;
int maxAge=0, maxName=-1;
int dataNum;
printf("How many people? :");
if(scanf("%d",&dataNum)!=1)return 1;
peopleName=malloc(sizeof(char[20])*dataNum);
peopleAge=malloc(sizeof(int)*dataNum);
for(i=0;i<dataNum;i++)
{
printf("Name & Age %d :",i+1);
scanf("%s",peopleName[i]);
scanf("%d",&peopleAge[i]);
if(peopleAge[i]>maxAge)
{
maxAge=peopleAge[i];
maxName=i;
}
}
printf("%s %d", peopleName[maxName],peopleAge[maxName]);
free(peopleName);
free(peopleAge);
return 0;
}
Also please note that:
You should pass char*, not char(*)[20], for %s in scanf
peopleAge[maxAge] may be out of bounds. maxName (or other name but same role) should suit here.

sort/search in stack [duplicate]

This question already has an answer here:
How to sort an array of structs in C?
(1 answer)
Closed 8 years ago.
I have created a stack system in C
It takes the First Name, Last name, and an employee number and the program runs fine.
#include<stdio.h>
#include<conio.h>
#define MAX 20
struct system
{
char first_name[15];
char surname[15];
}employee[20], temp;
int stack[MAX],front=-1,top=-1;
int i;
void push_element();
void pop_element();
void display_stack();
void display_first();
int main()
{
int option;
printf("STACK PROGRAM");
do
{
printf("\n\n 1.Push an element");
printf("\n 2.Pop an element");
printf("\n 3.Display stack");
printf("\n 4.Display first");
printf("\n 5.Display last");
printf("\n 6.Exit");
printf("\n Enter your choice: ");
scanf("%d",&option);
switch(option)
{
case 1: push_element();
break;
case 2: pop_element();
break;
case 3: display_stack();
break;
case 4: display_first();
break;
case 5: display_last();
break;
case 6: return 0;
}
}while(option!=6);
}
void push_element()
{
printf("\n Enter the first name: ");
scanf("%s",employee[i].first_name);
printf("\n Enter the Last name: ");
scanf("%s",employee[i].surname);
int num;
printf("\n Enter the employee number: ");
scanf("%d",&num);
i++;
if(front==0 && top==MAX-1)
printf("\n You have entered more than 20. Please delete a current input to make room. ");
else if(front==-1&&top==-1)
{
front=top=0;
stack[top]=num;
}
else if(top==MAX-1 && front!=0)
{
top=0;
stack[top]=num;
}
else
{
top++;
stack[top]=num;
}
}
void pop_element()
{
top--;
return top;
}
void display_stack()
{
int i;
if(front==-1)
printf("\n No Employees to display");
else
{
printf("\n List of employees:\n\n ");
printf(" Employee number First Name Surname\n\n");
for(i=front;i<=top;i++)
{
printf(" %d \t\t %s \t %s\n", stack[i], employee[i].first_name, employee[i].surname);
}
}
}
void display_first()
{
int i;
if(front==-1)
printf("\n No Employees to display");
else
{
printf("\n The first Employee in the stack is:\n\n ");
printf(" Employee number First Name Surname\n\n");
for(i=front;i<=top;i++)
break;
{
printf(" %d \t\t %s \t %s\n", stack[i], employee[i].first_name, employee[i].surname);
}
}
}
void display_last()
{
int i;
if(front==-1)
printf("\n No Employees to display");
else
{
printf("\n The last Employee in the stack is:\n \n");
printf(" Employee number First Name Surname\n\n");
for(i=top;i<=front;i++)
break;
{
printf(" %d \t\t %s \t %s\n", stack[i], employee[i].first_name, employee[i].surname);
}
}
}
I for the life of me cannot figure out how to sort the stack. I have tried other pieces of code and many different things, but none of them have came close to finding it
But I am wanting to sort it by alphabetical order. So not by entry time or Employee number, but by the First initial of the Surname
A search function is also required for this, and to be done by Employee number.
I have looked online, and the use of sorting and searching in a stack isn't a common thing, but I required to have it.
I am not good at C and I am fairly new to it. Any tips or things that may help me greatly would be appreciated. Also I apologies for any formatting errors, I'm fairly new to programming altogether and using software.
Your data structure doesn't directly record an employee number. You have the array stack which records the employee number, and the array employee which records names. You need to preserve the relationship stack[i] contains the employee number for employee[i] which means any sorting of the existing data structure has to sort two arrays in parallel. While it can be done, it is not the best way to fix the problems (and it is harder than it need be, and will require a custom sort function).
You should upgrade the data structure to include the employee number:
struct employee
{
int number;
char first_name[15];
char surname[15];
} employee[20];
Note that I've retagged the structure as struct employee (instead of struct system) since it seems more relevant to the content of the structure.
You can then use the qsort() function from the standard C library (declared in <stdlib.h>) and the techniques documented in the proposed duplicate (How to sort an array of structs in C?) to sort the data straight-forwardly. It is also easier to write your searching code.
You can also clean up the display code; you can have a single function that is passed an employee structure (or pointer to one). It will contain a single printf() statement that formats the data correctly. This saves you writing the same elaborate printf() code 3 times, making it easier to fix the formatting if (when) you need to do so. You can also avoid using tabs in the output (generally a good idea), leading to:
void print_employee(const struct employee *emp)
{
printf("%8d %-15s %-15s\n", emp->number, emp->first_name, emp->surname);
}
This will produce well aligned output unless your employee number grows to more than 8 digits (in which case, change the 8 to 10 or whatever). You can also generalize one step further if you wish, passing a FILE *fp argument to the function, and using fprintf(fp, "…", …) instead of printf().
You call the function:
print_employee(&employee[i]);
You might also consider a function to print the headings since you have that function call 3 times. Alternatively, you might just have a constant string at file scope that contains the correct headings which you use in 3 places. You could do that with the print_employee() function too; have a constant string at file scope that is the format you use.
Also, in your display_first() and display_last() functions, the loops are curious. You've written:
for(i=front;i<=top;i++)
break;
{
printf(" %d \t\t %s \t %s\n", stack[i], employee[i].first_name, employee[i].surname);
}
You should realize (on review) that this is equivalent to:
i = front;
printf(" %d \t\t %s \t %s\n", stack[i], employee[i].first_name, employee[i].surname);
(If front is larger than top, then i = front is the only part of the loop executed; otherwise, the break is executed; either way, after the loop, i == front.)

Error while assigning values to a struct using pointers

I am new to C and have been trying to get this simple code run which makes use of pointers to struct for calculating the average of grades entered. After entering the maths grade, the program throws an error and stops. What am I doing wrong.
Its also my first post in here, so please bear with me for any inconsistencies. Thanks!
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
char *name;
int mathGrade,scienceGrade,historyGrade,englishGrade;
}reportCard;
void average(reportCard *rc)
{
int avg = (rc->mathGrade +rc->scienceGrade+rc->historyGrade+rc->englishGrade)/4;
printf("The overall grade of %s is: %i ",rc->name, avg);
}
int main()
{
reportCard rc;
printf("Enter the Students Last name: ");
char studentName[20];
scanf("%s", studentName);
rc.name=studentName;
printf("Math Grade: \n");
scanf("%i", rc.mathGrade);
printf("Science Grade: \n");
scanf("%i", rc.scienceGrade);
printf("History Grade: \n");
scanf("%i", rc.historyGrade);
printf("English Grade: \n");
scanf("%i", rc.englishGrade);
average(&rc);
return 0;
}
You get an error because reading primitives with scanf requires pointers:
scanf("%i", &rc.mathGrade);
scanf("%i", &rc.scienceGrade);
// ^
// |
// Here
// ...and so on
scanf thinks that an uninitialized int that you pass is a pointer, and tries to write it, which results in an error.
In addition, you need to protect against buffer overruns on reading strings, like this:
scanf("%19s", studentName); // you allocated 20 chars; you need one for null terminator

Resources