Array of Structures in C. not linked list - c

I am having trouble making an array of structures. I want to store data regarding multiple students and take input using the execution of the program. Then output the memory address of persons name with highest marks.
I tried getting to know the answers on similar issues on site, to no help.
The code I have written is
the struct
struct student{
char name;
int marks;
};
and the function is
int num,max = 0,i;
printf("Number of students?\n");
scanf("%d", &num);
struct student* students = (struct student*)malloc (num* (sizeof(struct student)));
for (int x = 0; x < num; x++)
{
printf("Enter Name\n");
scanf("%c" , &students[x].name);
printf("Enter Marks\n");
scanf ("%d" , &students[x].marks);
}
for (i = 1; i < num; i++)
{
if (students[max].marks<students[i].marks)
{
max = i;
}
}
printf("The Memory Add for %c is %p\n", students[max].name , &students[max].name );
It is a part of menu driven program. It goes into a weird loop after line 5 in function code. And i can't create a doubly linked list for the same.
Edit 1
These are the changes i made to struct and func
struct student{
char name[20];
int marks;
};
void memadd(){
int num,max = 0,i, mark;
printf("Number of students?\n");
scanf("%d", &num);
struct student* students = (struct student*)malloc (num* (sizeof(struct student)));
for (int x = 0; x < num; x++)
{
printf("Enter Name\n");
scanf("%s" , &students[x].name);
printf("Enter Marks\n");
scanf ("%d" , &mark);
students[x].marks = mark;
}
for (i = 1; i < num; i++)
{
if (students[max].marks<students[i].marks)
{
max = i;
}
}
printf("The Memory Add for %s is %p\n", students[max].name , &students[max].name );
It is giving an array at input of the name. "format specifies type 'char ' but the argument has
type 'char ()[20]'"
How do I make the format to be char * [20]?
Edit 2
The final working code after correcting the char name to being a character array
And issue with scanning of names.
struct student{
char name[20];
int marks;
};
int num,max = 0,i, mark;
printf("Number of students?\n");
scanf("%d", &num);
struct student* students = (struct student*)malloc (num* (sizeof(struct student)));
for (int x = 0; x < num; x++)
{
printf("Enter Name\n");
scanf("%19s" , students[x].name);
printf("Enter Marks\n");
scanf ("%d" , &mark);
students[x].marks = mark;
}
for (i = 1; i < num; i++)
{
if (students[max].marks<students[i].marks)
{
max = i;
}
}
printf("The Memory Add for %s is %p\n", students[max].name , &students[max].name );
However, what if I wish to print the address in Hex numbers? or the one that am getting is hex already.?
Because I got an output of The Memory Add for XYZ is 0x7fb340c03928

The problem is with the student name being a char and
scanf("%c" , &students[x].name);
What happens is, you read in the number of students with
scanf("%d", &num);
Now you have read num, but there is still a newline in the input buffer.
Then you try to read a character with %c, but this reads the remaining newline.
When you change the student's name to a character array, e.g.
struct student{
char name[20];
int marks;
};
and read the name with
scanf("%19s" , students[x].name);
it will skip the remaining whitespace/newline and read the name as it should.

Related

What this error mean : expression must have pointer to object type but it has type struct add_stock in c

#include <stdio.h>
int i, n;
struct add_stock
{
char fullname[30];
int stocks;
char com_name[30];
int shares;
float price;
float total;
int totalmoney;
} add;
int main()
{
printf("Enter full name : ");
scanf(" %[^\n]s", add.fullname);
printf("Enter the no. of stocks you want to purchased : ");
scanf("%d", &n);
for (i = 0; i < n; i++)
{
printf("Enter the name of the company : ");
scanf(" %[^\n]s", add[i].com_name);
printf("Enter the no. of shares you want to purchased : ");
scanf("%d", &add[i].shares);
printf("Enter the price of each share : ");
scanf("%f", &add[i].price);
add.total = add.shares * add.price;
printf("Toatl money invested in this stock : ");
scanf("%f", &add[i].total);
}
printf("Total money invested : ");
scanf("%d", add.totalmoney);
return 0;
}
In question it's add_stock , not add stock , i write like this becoz it's not accepting question.
So, i get error for "add" saying subscripted value is neither array nor pointer nor vector.
To declare an array of strucuture, you need to define the variable as below,
struct add_stock
{
char fullname[30];
int stocks;
char com_name[30];
int shares;
float price;
float total;
int totalmoney;
} add[20];
this makes the add as an array of add_stock elements.
then you can access it as, add[0].total, add[1].price and so on.
If you want to declare an array that need to be having dynamic number of elements, you can do so as below.
struct add_stock* arStock;
//allocate memory to hold 10 elements
arStock = (add_stock*)malloc( 10 * sizeof(struct add_stock));
arStock[0]->total=10; //access it with ->, instead of .

Proper use of structures and pointers

I have to declare a vector with the "struct" type which, for every n students, it creates a value for the group that student belongs to (which is like a counter), their names and their grades.
The program has to output the name of the students with the highest grade found in these groups. I have to allocate the vector on the heap (I only know the theoretical explanation for heap, but I have no idea how to apply it) and I have to go through the vector using pointers.
For example if I give n the value 4, there will be 4 students and the program will output the maximum grade together with their names as shown here.
This will output Ana 10 and Eva 10.
I gave it a try, but I have no idea how to expand it or fix it so I appreciate all the help I can get with explanations if possible on the practical application of heap and pointers in this type of problem.
#include <stdio.h>
#include <stdlib.h>
struct students {
int group;
char name[20];
int grade;
};
int main()
{
int v[100], n, i;
scanf("%d", n);
for (i = 0; i < n; i++) {
v[i].group = i;
scanf("%s", v[i].name);
scanf("%d", v[i].grade);
}
for (i = 0; i < n; i++) {
printf("%d", v[i].group);
printf("%s", v[i].name);
printf("%d", v[i].grade);
}
return 0;
}
Here I was just trying to create the vector, nothing works though..
It appears, int v[100]; is not quite what you want. Remove that.
You can follow either of two ways.
Use a VLA. After scanning the value of n from user, define the array like struct students v[n]; and carry on.
Define a fixed size array, like struct students v[100];, and use the size to limit the loop conditions.
That said,
scanf("%d", n); should be scanf("%d", &n);, as %d expects a pointer to integer type argument for scanf(). Same goes for other cases, too.
scanf("%s", v[i].name); should better be scanf("%19s", v[i].name); to avoid the possibility of buffer overflow by overly-long inputs.
Even though you are asking for the number of students (groups) using scanf, you hardcoded the upper bound of this value using v[100]. So, I passed your input variable n (the number of students) to malloc in order to allocate the space you need for creating an array of n students.
Also, I used qsort to sort the input array v where the last element would be the max value. Here qsort accepts an array of structs and deference the pointers passed to the comp function to calculate the difference of the comparison.
Finally, I printed the sorted array of structs in the last loop.
#include <stdio.h>
#include <stdlib.h>
struct students {
int group;
char name[20];
int grade;
};
int comp(const void *a, const void *b)
{
return ((((struct students *)a)->grade > ((struct students *)b)->grade) -
(((struct students *)a)->grade < ((struct students *)b)->grade));
}
int main()
{
int n;
printf("Enter number of groups: ");
scanf("%d", &n);
printf("\n");
struct students *v = malloc(n * sizeof(struct students));
int i;
for(i = 0; i < n; i++)
{
v[i].group = i;
printf("\nName: ");
scanf("%s", v[i].name);
printf("Grade: ");
scanf("%d", &v[i].grade);
}
qsort(v, n, sizeof(*v), comp);
for(i = 0; i < n; i++)
{
printf("Group %d, Name %s, grade %d\n", v[i].group, v[i].name, v[i].grade);
}
return (0);
}
You need to replace the standalone array v[100], with an array of structs referencing your structure:
struct students v[100];
However, if you want to use malloc to allocate memory on the heap, you will need to do something like this:
struct students *students = malloc(n * sizeof(struct students));
/* Check void* return pointer from malloc(), just to be safe */
if (students == NULL) {
/* Exit program */
}
and free the requested memory from malloc() at the end, like this:
free(students);
students = NULL;
Additionally, adding to #Sourav Ghosh's answer, it is also good to check the return value of scanf(), especially when dealing with integers.
Instead of simply:
scanf("%d", &n);
A more safe way is this:
if (scanf("%d", &n) != 1) {
/* Exit program */
}
With all this said, your program could look something like this:
#include <stdio.h>
#include <stdlib.h>
#define NAMESTRLEN 20
typedef struct { /* you can use typedef to avoid writing 'struct student' everywhere */
int group;
char name[NAMESTRLEN+1];
int grade;
} student_t;
int
main(void) {
int n, i;
printf("Enter number of students: ");
if (scanf("%d", &n) != 1) {
printf("Invalid input.\n");
exit(EXIT_FAILURE);
}
student_t *students = malloc(n * sizeof(*students));
if (!students) {
printf("Cannot allocate memory for %d structs.\n", n);
exit(EXIT_FAILURE);
}
for (i = 0; i < n; i++) {
students[i].group = i;
printf("Enter student name: ");
scanf("%20s", students[i].name);
printf("Enter students grade: ");
if (scanf("%d", &(students[i].grade)) != 1) {
printf("Invalid grade entered.\n");
exit(EXIT_FAILURE);
}
}
printf("\nStudent Information:\n");
for (i = 0; i < n; i++) {
printf("Group: %d Name: %s Grade: %d\n",
students[i].group,
students[i].name,
students[i].grade);
}
free(students);
students = NULL;
return 0;
}

Copying variables for an array to another array with the array being a struct with chars

First off Ill show you how I'm defining struct StudentRecord
typedef struct{
char SN[10];
char lname[20];
float GPA;
}StudentRecord;
Now the point of this is to read in information from a .dat file which this program does successfully but when I go to save the array that I have made (more on this below) it give me a very weird output this code has a 2 global variables
StudentRecord* studentRecordList;
int studentRecordSize;
the studentRecordSize is going to be the first input line from the file, the function for reading the files looks like the following.
void load_records(){
FILE* student_file = fopen("StudentRecordFile.dat", "r");
if(student_file == 0){
perror("cannot open StudentRecordFile.dat in load_records");
}
//free existing student list
if(studentRecordList != 0){
free(studentRecordList);
}
//get number of students in the list
fscanf(student_file, "%d",&studentRecordSize);
//create and load new student list
studentRecordList = (StudentRecord*)malloc(studentRecordSize * sizeof(StudentRecord));
int i;
for(i = 0; i < studentRecordSize;i++){
fscanf(student_file,"%s %s %s %f", studentRecordList[i].SN,studentRecordList[i].fname,studentRecordList[i].lname,&studentRecordList[i].GPA);
}
fclose(student_file);
}
Now from the driver you are given 4 options to 0-exit(also saves to the file), 1-find(just a search through the array), 2-add(add another student to the array), 3-modify, 4-delete.
the function for adding a student to the array is where I'm getting my problem for some reason it is messing up my output file and changing all my GPA variables to 0.000000 and leaving random blank spaces throughout the document. Anyway here is what it looks like.
void add_record(){
char fname[20];
char lname[20];
char SN[10];
float GPA;
printf("Enter the Students first Name: ");
scanf("%s", &fname);
printf("\nEnter the Students last Name: ");
scanf("%s", &lname);
printf("\nEnter the Students number: ");
scanf("%s", &SN);
printf("\nEnter the Students GPA: ");
scanf("%f", &GPA);
StudentRecord* tempList;
tempList = (StudentRecord*)malloc(studentRecordSize * sizeof(StudentRecord));
int i;
studentRecordSize = studentRecordSize+1;
for(i = 0; i < studentRecordSize -1; i ++){
tempList[i].GPA = studentRecordList[i].GPA;
strncpy(tempList[i].SN, studentRecordList[i].SN,10);
strncpy(tempList[i].fname, studentRecordList[i].fname,20);
strncpy(tempList[i].lname , studentRecordList[i].lname,20);
}
printf("%f", &tempList[i].GPA );
free(studentRecordList);
studentRecordList = (StudentRecord*)malloc(studentRecordSize * sizeof(StudentRecord));
for(i=0; i < studentRecordSize; i ++){
//adds the new student at the end of the array.
if(i == studentRecordSize){
strncpy(*studentRecordList[i].fname, &fname,20);
strncpy(*studentRecordList[i].lname, &lname,20);
studentRecordList[i].GPA = GPA;
strncpy(*studentRecordList[i].SN, &SN,10);
}
strncpy(studentRecordList[i].fname, tempList[i].fname,20);
strncpy(studentRecordList[i].lname , tempList[i].lname,20);
studentRecordList[i].GPA = tempList[i].GPA;
strncpy(studentRecordList[i].SN , tempList[i].SN,10);
}
free(tempList);
}
Also if your curious here is what my save_records function looks like otherwise ignore.
void save_records(){
FILE* student_file = fopen("StudentRecordFile.dat", "w");
if(student_file == 0){
perror("cannot open StudentRecordFile.dat in load_records");
}
fprintf(student_file,"%d\n",studentRecordSize);
int i;
for(i = 0; i < studentRecordSize; i++){
fprintf(student_file,"%s\n%s\n%s\n%f\n", studentRecordList[i].SN, studentRecordList[i].fname, studentRecordList[i].lname, &studentRecordList[i].GPA);
}
}
If you need anything else let me know and ill be sure to add it, thanks.
Please try this:
in save_records() open your file binary
fopen(student_file , "wb");
then use fwrite to write the record
fwrite( &studentRecordList[i] , sizeof( studentRecordList) , 1 , student_file );
It is also easier, if you can, to write the number of records to a separate file that you open text.
This code has some problems:
for(i=0; i < studentRecordSize; i ++){
//adds the new student at the end of the array.
if(i == studentRecordSize){ // <- This can never be TRUE !!!
strncpy(*studentRecordList[i].fname, &fname,20); // Wrong
strncpy(*studentRecordList[i].lname, &lname,20);
studentRecordList[i].GPA = GPA;
strncpy(*studentRecordList[i].SN, &SN,10);
}
// Should the code below be an else ?
// If not you'll access outside tempList
strncpy(studentRecordList[i].fname, tempList[i].fname,20);
strncpy(studentRecordList[i].lname , tempList[i].lname,20);
studentRecordList[i].GPA = tempList[i].GPA;
strncpy(studentRecordList[i].SN , tempList[i].SN,10);
}
Maybe you wanted to do:
for(i=0; i < studentRecordSize; i ++){
if(i == (studentRecordSize-1)){
// Add the new record
strncpy(studentRecordList[i].fname, fname,20);
strncpy(studentRecordList[i].lname, lname,20);
studentRecordList[i].GPA = GPA;
strncpy(studentRecordList[i].SN, SN,10);
}
else
{
// Copy from the temp list
strncpy(studentRecordList[i].fname, tempList[i].fname,20);
strncpy(studentRecordList[i].lname , tempList[i].lname,20);
studentRecordList[i].GPA = tempList[i].GPA;
strncpy(studentRecordList[i].SN , tempList[i].SN,10);
}
}
A more simple version of the add function could be:
void add_record(){
char fname[20];
char lname[20];
char SN[10];
float GPA;
printf("Enter the Students first Name: ");
scanf("%s", &fname);
printf("\nEnter the Students last Name: ");
scanf("%s", &lname);
printf("\nEnter the Students number: ");
scanf("%s", &SN);
printf("\nEnter the Students GPA: ");
scanf("%f", &GPA);
StudentRecord* tempList;
tempList = (StudentRecord*)malloc(studentRecordSize * sizeof(StudentRecord));
int i;
for(i = 0; i < studentRecordSize; i ++){
tempList = studentRecordList[i];
}
free(studentRecordList);
studentRecordSize = studentRecordSize+1;
studentRecordList = (StudentRecord*)malloc(studentRecordSize * sizeof(StudentRecord));
for(i=0; i < (studentRecordSize-1); i ++){
studentRecordList[i] = tempList[i];
}
free(tempList);
// Add the new record
strncpy(studentRecordList[(studentRecordSize-1)].fname, fname,20);
strncpy(studentRecordList[(studentRecordSize-1)].lname, lname,20);
studentRecordList[(studentRecordSize-1)].GPA = GPA;
strncpy(studentRecordList[(studentRecordSize-1)].SN, SN,10);
}

Creating an array of struct (c)

i've created a struct "Employee"
#define MAX_SIZE 20
typedef struct Employee{
char name[MAX_SIZE];
int s;
int e;
} employee_s;
and i need to create an array of 2 employees and ask the user to initialize them, nothing i try seem to work,
void main()
{
int i, s, e;
char name[10];
Employee* e[3];
*e = (Employee*)malloc(sizeof(Employee)*ARR_SIZE);
for(i=0; i < 3; i++)
{
fflush(stdin);
puts("Please enter Employee's name:");
scanf("%c",&name);
*e[i]->name = name;
puts("Please enter Employee's salary:");
scanf("%d",&s);
*e[i]->s= s;
puts("Please enter Employee's experience:");
scanf("%d",&e);
*e[i]->e=e;
}
}
p.s: i dont have to use dynamic allocation,
what do i do wrong?
thank you!
There are several errors here:
Employee is not a valid type. struct Employee is, and so is employee_s.
e is defined in multiple places
When reading in name, use %s (for a string), not %c (for a char)
Your employee array is defined as an array of pointers. That's probably not what you want. You just need an array. No call to malloc either.
Never fflush(stdin). It's undefined behavior.
In your scanf calls, put a space as the first character in the string. That will allow any newlines to be passed over.
The result:
int main()
{
int i;
employee_s e[3];
for(i=0; i < 3; i++)
{
puts("Please enter Employee's name:");
scanf(" %s",&e[i].name);
puts("Please enter Employee's salary:");
scanf(" %d",&e[i].s);
puts("Please enter Employee's experience:");
scanf(" %d",&e[i].e);
}
for(i=0; i < 3; i++) {
printf("emp %d: name=%s, sal=%d, exp=%d\n", i, e[i].name, e[i].s, e[i].e);
}
}
You've got your declaration backward. This:
typedef struct Employee{
char name[MAX_SIZE];
int s;
int e;
} employee_s;
declares a type named employee_s to be equivalent to struct Employee, and furthermore declares struct Employee. You appear to want this, instead:
typedef struct employee_s {
char name[MAX_SIZE];
int s;
int e;
} Employee;
In this case you can omit employee_s from that if you wish; perhaps that would be less confusing.
Moreover, you are going about your allocation in a very strange way, especially since you don't require dynamic allocation. Why not just do this:
Employee e[3];
? Then you can (and should) skip malloc() altogether. You will then refer to the members of the array elements via the form e[0].name, etc..
You can do this easily without dynamic memory allocation as follows.
#include <stdio.h>
#define MAX_SIZE 20
typedef struct Employee{
char name[MAX_SIZE];
int s;
int e;
} employee_alias;
int main(void) {
int i;
employee_alias e[3];
for(i=0; i < 3; i++)
{
puts("Please enter Employee's name:");
scanf("%s",e[i].name);
puts("Please enter Employee's salary:");
scanf("%d",&e[i].s);
puts("Please enter Employee's experience:");
scanf("%d",&e[i].e);
printf("Entered Data\n");
printf("Name : %s\n",e[i].name);
printf("Salary : %d\n",e[i].s);
printf("Experience : %d\n",e[i].e);
}
return 0;
}

C store values in an array

My program reads the following data: Date, Distance and Time.
So for example an input would look like:
Date: 10.10.2013
Distance (m): 500
Time (HH:MM:SS): 01:20:05
I want to store all this information in an array. The problem is that I want the user to input date, distance and time several times and the program has to save all the data in an array.
I can't store it like this, because then how would I know which index is the date index? And how should I store the time? I can't store it with :.
arr[0] = 10.10.2013
arr[1] = 500
arr[2] = 012005
arr[3] = 22.10.2013
arr[4] = 200
arr[5] = 000510
You can make a struct:
struct Data{
Date date;
Distance distance;
Time time;
}
Then declare an array of Data and use it like that:
Data arr[5];
arr[0].date = //some date;
arr[0].distane =//some distance
arr[0].time=//some time
Because the type of data you will need to store, it needs type char, so it can be stored in strings. (i.e. "10.10.2013")
First, Define a struct PARAM:
typedef struct {
char date[20];
char distance[20];
char time[20];
} PARAM;
use PARAM to create an array of your struct:
PARAM param[20];
Now, you can use it like this for example:
int main(void)
{
strcpy(param[0].date, "10.10.2013");
strcpy(param[0].time, "05:02:10");
strcpy(param[0].distance, "500");
//and so on for all the struct array elements, 0 through 20
return 0;
}
Or, better yet, using printf() and scanf() statements as necessary, you can prompt the user for input in a loop, and store in your struct array:
int main(void)
{
int i;
for(i=0;i<20;i++)
{
printf("enter date %d:", i+1);
scanf("%s", param[i].date);
printf("enter distance %d:", i+1);
scanf("%s", param[i].distance);
printf("enter time %d:", i+1);
scanf("%s", param[i].time);
}
return 0;
}
EDIT Regarding question in comment Therefore I guess its best to store them in date.day, date.month and date.year. Right? That approach would work, and I include it below, but it is a little more tedious to enter data that way. I included a second example below that might improve both, entering data, and storing data.
So, Per your comment, two ways jump to mind:
ONE, create struct members that contain the discrete members of time and date as integers: i.e.
typedef struct {
int day;
int month;
int year;
int hour;
int minute;
int second;
}TIMEDATE;
Use this struct as a member of the PARAM struct;
typedef struct {
int distance;
TIMEDATE timedate;
}PARAM;
PARAM param[20];
Now, just modify and expand the example of the last main() function to include scanning in values for the new struct members. This will be more tedious for the person using your program, but will allow you to keep all the input values as numbers as you have indicated.
//Note the changes in scanf format specifiers for int, "%d":
// in all the statements
int main(void)
{
int i;
for(i=0;i<20;i++)
{
printf("enter date %d:", i+1);
scanf("%d", &param[i].timedate.day);
printf("enter time %d:", i+1);
scanf("%d", &param[i].timedate.month);
printf("enter time %d:", i+1);
scanf("%d", &param[i].timedate.year);
printf("enter time %d:", i+1);
scanf("%d", &param[i].timedate.hour);
printf("enter time %d:", i+1);
scanf("%d", &param[i].timedate.minute);
printf("enter time %d:", i+1);
scanf("%d", &param[i].timedate.second);
printf("enter time %d:", i+1);
scanf("%d", &param[i].distance);
}
return 0;
}
Two, modify the first approach to include using strings AND integers, all in the same struct. This will make it easier for the user user to enter time and date information, and possible for you to manipulate the data easier. And a bonus, it will demonstrate how to parse the user input string data into integer data.
typedef struct {
char date[20];//keep as char
char time[20];//keep as char
int distance; //changed to int
TIMEDATE timedate;//container for in data
} PARAM;
//use PARAM to create an array of your struct:
PARAM param[20], *pParam; //create a pointer to pass
int GetIntData(PARAM *p, int index);//prototype for new function
//Note the changes in scanf format specifiers for int, "%d":
// in all the statements
int main(void)
{
int i, loops;
pParam = &param[0]; //initialize pointer to struct
printf("How many sets of data would you like to enter? :");
scanf("%d", &loops);
for(i=0;i<loops;i++)
{
printf("enter date (eg:MM.DD.YYYY): %d:", i+1);
scanf("%s", pParam[i].date);
printf("enter time (eg HH:MM:SS): %d:", i+1);
scanf("%s", pParam[i].time);
printf("enter distance %d:", i+1);
scanf("%d", &pParam[i].distance);
GetIntData(pParam, i);
}
return 0;
}
//reads string members into integer members
int GetIntData(PARAM *p, int index)
{
char *buf=0;
if(strstr(p[index].date, ".")==NULL) return -1;
p[index].timedate.month = atoi(strtok(p[index].date, "."));
p[index].timedate.day = atoi(strtok(NULL, "."));
p[index].timedate.year = atoi(strtok(NULL, "."));
if(strstr(p[index].time, ":")==NULL) return -1;
buf=0;
p[index].timedate.hour = atoi(strtok(p[index].time, ":"));
p[index].timedate.minute = atoi(strtok(NULL, ":"));
p[index].timedate.second = atoi(strtok(NULL, ":"));
return 0;
}

Resources