How do I use a structure? - c

Ok firstly I'll explain my assignment. For this assignment I have to use dynamic memory allocation which I am having no problems with. What I am having a problem with is figuring out the correct way to work my assignment. For my assignment I need to create a program that prompt the user to enter how many students they have then ask for the following information; Student ID, Birthdate, and Phone number. I need to use a loop to prompt the user to enter all the students information. I need to create a loop that will scan through all the student IDs and find the oldest student using their birthdate (The loop must be able scan through more then 3 students).
Here is my code, I've gotten some suggestions and even bits of code from you guys, but after implementing them I'm even more confused on what I should do. Please take a look at it and critique me.
EDIT: I also added in on the code where I'm receiving and error
Thank you.
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int * studentData= NULL;
int * studentDataType=NULL;
int students;
int studentID;
int year;
int month;
int day;
long long phone;
printf("How many students are you entering records for:\n");
scanf("%d", &students);
studentData=(int*)malloc((sizeof(int)*students));
struct studentDataType
{
int studentID;
int year;
int month;
int day;
long long phone;
};
//invalid operands to binary * (have 'int' and 'int *')
studentDataType *studentData = (studentDataType*)malloc(numberOfStudents *sizeof(studentData));
for (int i = 0 ; i < students ; ++i)
{
printf("%d, %d, %d, %d, %d\n", studentID, year, month, day, phone);
}
}

You're redefining studentData
int * studentData= NULL;
then later
studentDataType *studentData = (studentDataType*)malloc(numberOfStudents * sizeof(studentData));
You should declare the studentDataType struct first (outside of main() ) then use it in your original declaration

To see the task it is better at least for the first time to write some block-scheme of what you have to do in a program. In your case:
Read data from user (each structure).
Increase array size, add new structure.
Loop 1-2 until input user finish adding new people (needs some condition here to finish).
Find necessary structure and print it.
So the first step is to read information from user. You can use scanf():
In the simplest way you can do that step-by-step for each field:
#include <stdio.h>
...
int value;
scanf("%d", &value);
...
In case of success this function should return number of items it reads (1 in your case).
For phone you should use scanf("%ld", &phone).
To resize array use function realloc() (#include :
realloc(&ptr_to_array, new_size);
Each elements of the array is a pointer to structure "student".
Next steps are similar.

The first problem is that you have variable names the same as the name of the type. Although you can have that in C to a certain extent, like:
typedef int x;
x foo (x x)
{
return x;
}
It might be a good idea not to do this for the readability purposes. So in your case you have:
int * studentData= NULL;
int * studentDataType= NULL;
which is a variable name, then you have:
struct studentDataType ...
which is a name of the type (should be used as struct studentDataType, not without struct as you do); finally
studentDataType *studentData = ...
is treated by the compiler as an operation on two variables, not a type declaration as you would expect. So your memory allocation needs to be:
struct studentDataType *studentData = malloc(numberOfStudents *sizeof(struct studentData));
Which brings a problem that you redefine studentData, which you declared in the beginning of the program, and "numberOfStudents" is not defined, probably you wanted to write "students" instead.
As for the reading data with scanf, see the previous comment.

Related

A global struct pointer is used, but it does not take input. In C

The input lines are marked beside.
Here,
*ptr is a global struct pointer.
In the main function, the get_data() function is called but it does not take any input rather the program terminates.
#include<stdio.h>
#include<stdlib.h>
struct detail
{
int present, absent, credit, left_weeks;
};
struct detail *ptr; // global
void get_data()
{
printf("\nYou have opted for Entering the data \n");
printf("\nEnter the number of presents - ");
scanf("%d",&ptr->present); // First input
printf("\nEnter the number of absents - ");
scanf("%d",&ptr->absent); // Second input
printf("\nEnter the subject credit - ");
scanf("%d",&ptr->credit); // Third input
printf("\nEnter the number of weeks left - ");
scanf("%d",&ptr->left_weeks); // Fourth input
}
int main()
{
get_data();
}
I have checked in visual studio code and also an online compiler.
Could anyone help.
ptr points nowhere. And there is no variable of type struct detail in this code.
You probably want this:
#include<stdio.h>
#include<stdlib.h>
struct detail
{
int present, absent, credit, left_weeks;
};
struct detail foo; // << the actual variable you forgot
struct detail *ptr = &foo; // globalptr points to foo
...
and all your scanfs are wrong, the %d specifier wants a pointer to int but you provide an int.
You want this:
scanf("%d", &ptr->present);
^you forgot this
That being said, your approach is overly complicated, you probably just want this:
scanf("%d", &foo.present);
and remove the global ptr pointer alltogether.
already answered but I want to elaborate.
struct detail *ptr;
creates a pointer whose job is to point at an instance of detail. but you have not told it which one to point at (Imagine you had several instances of details in you program). In fact you dont have any instances of detail yet.
So you have to create an instance of detail
On the stack and set ptr to point at it
int main (..){
...
struct detail d;
ptr = &d;
On the heap
int main (..){
...
struct detail *d = malloc(sizeof(struct detail));
ptr = d; // d is a pointer already here
Or static global
struct detail d;
....
int main(..){
....
ptr = &d;

Pass a string in a struct to a function and return it

I want to return the name of the smallest city population-wise, if it is the second city. (Please don't mind the if statement, I know it's bland), the missing return is what bothers me.
I assume I should declare a pointer inside the function rSmallestCity, like *rtrn but I guess the source variable is destroyed before it is used?
typedef struct Coordinate{
int x,y;
}Coordinate;
typedef struct city{
char name[20];
int population;
Coordinate coordinates;
}city;
char *rSmallestCity(city **cl, int n)
{
char *rtrn = NULL;
if(cl[n-2]->population>cl[n-1]->population)
{
rtrn = &cl[n-1]->name;
}
return rtrn;
}
int main()
{
city c1 ={.name="Mumbai", .population=310, .coordinates.x=3, .coordinates.y=4};
city c2 ={.name="Delhi", .population=300, .coordinates.x=3, .coordinates.y=2};
city *clist[2];
clist[0]=&c1;
clist[1]=&c2;
printf("\n%s is smallest\n",rSmallestCity(clist,2));
}
warning: assignment to 'char ' from incompatible pointer type 'char ()[20]' [-Wincompatible-pointer-types]|
I assume I should declare a pointer inside the function rSmallestCity, like *rtrn but I guess the source variable is destroyed before it is used?
A good question. And your assumption is correct. Creating a variable inside a function it's existence ends upon leaving the function. But in this case, because the struct member name is already a char * you do not need to create another variable. Just return c1.name. (see code example below.)
A few other suggestions:
In the struct declaration:
typedef struct Coordinate{
int x,y;
}Coordinate;
You've used the same symbol (Coordinate) for the struct name, and for it's typedef. This is not a good practice. If you need both a struct name and a typedef, pick different symbols. BTW, in this this example, only one or the other is needed. Say you pick the typedef, then the struct is completely defined by:
typedef struct {
int x,y;
}Coordinate;
That suggestion applies to both struct declarations in your example code.
The signatures for the main function do not include int main(){...} rather
int main(void){..., return 0;} and int main(int argc, char *argv[]){..., return 0;}
The following code example illustrates some of the other suggestions for improvements in comments under your post,
typedef struct {
int x,y;
}Coordinate;
typedef struct {
char name[20];
int population;
Coordinate coordinates;
}city;
//return char * rather than char to allow for full null terminated char array (string)
char * rSmallestCity(city c1[],int cityCount)//generisize function prototype to
{ //to easily accommodate bigger arrays if needed
long long size, sizeKeep = 8e9; //index and population. initialize larger than possible population
int indexKeep = 0;
//note you do not need to define a char *, the struct already contains one
for(int i=0; i<cityCount; i++)//use a loop rather than a single comparison, keep the smalles
{
size = c1[i].population;
sizeKeep = (size < sizeKeep) ? indexKeep = i, size : sizeKeep;
}
printf("\n%s\n",c1[indexKeep].name);
return c1[indexKeep].name;
};
int main(void)//use minimum signature for main, and call return before leaving.
{
//combining your original declarations and assignments for struct
//into a single declaration/definition.
city c1[] = {{.name="Mumbai", .population=310, .coordinates.x=3, .coordinates.y=4},
{.name="Delhi", .population=300, .coordinates.x=3, .coordinates.y=2}};
int cityCount = sizeof(c1)/sizeof(c1[0]);
printf("\n%s is smallest",rSmallestCity(c1, cityCount));
return 0;
};
The solution that I originally left in comment under OP (remove & in the line &cl[n-1]->name;) needs some explanations to avoid problems later.
(It is an educational answer not a full answer on pointers, array decay, ... And many examples can be found on stackoverflow. I tried to simplify)
Try this simple code.
int main()
{
char myString1[25]="Toulouse" ; // French City
printf("%p\n",myString1);
printf("%p\n",&myString1);
}
The output is the same, but an array name and the address of an array name are not the same. The array name is evaluated to the address of its first element. So it works in your case but a warning is issued during compilation and it is very important. Firstly, do not remove compilation warnings.
Now, try this code :
int main()
{
char myString1[25]="Toulouse" ; // French City
printf("%p\n",myString1+1);
printf("%p\n",&myString1+1);
}
The outputs are different. Because myString1 is evaluated to char* and &myString1 to char [25]. So +1, in the first, case adds one (sizeof char) to the pointer and in the other case, it adds 25.
Delete the "&" in the line:
rtrn = &cl[n-1]->name;
To extremely simplify, you assigned an "address of char[]" to a char*, but array syntax makes it work regardless.

C Using pointers with a 2D array of a struct and how to access them using pointers

#include <string.h>
#include <stdio.h>
struct student{
char last[25] ;
char first[25];
};
struct seating {
struct student **seat;
};
//Set the first and last name to default values
void student_init_default(struct student *s ) {
strcpy(s->last_name,"***");
strcpy(s->first_name,"***");
}
void seating(int rowNum, int columnNum, struct seating *a ){
//Instantiate a 2D array specfied by the parameters
struct student students[rowNum][columnNum];
a->seat = students;
//Initialize each element to the default
for(int rows = 0; rows < rowNum; rows++){
for(int columns = 0; columns < columnNum; columns++){
student_init_default(&students[rows][columns]);
}
}
}
void main() {
struct seating room;
struct student student;
int row, col, rowNum, columnNum;
char student_info[30];
// Ask a user to enter a number of rows for an classroom seating
printf ("Please enter a number of rows for an classroom seating.");
scanf ("%d", &rowNum);
// Ask a user to enter a number of columns for an classroom seating
printf ("Please enter a number of columns for an classroom seating.");
scanf ("%d", &columnNum);
// seating
seating(rowNum, columnNum, &room);
}
To start off, I am a beginner at C. My problem is using pointers. The main point in this code is to make a 2D array of the struct student and then fill in the array by setting the default as first and last name. What Im asking for is if someone can give a easy explanation or hints on how to connect the parameter, struct classroom_seating *a, with struct student **seating, along with the 2D array. Along with that, how would I use struct classroom_seating *a to access the 2D array? I do know the basics of pointers but I've been researching for hours and haven't found a connection to work.
I do know that this line printf("%s", listOfStudents[0][2].firstName); prints *** (assuming the user entered 3,3 for row/columns). It's that I don't know how I would be able to access that in later methods.
a->seat = students;
The compiler is explicit about the error
error: cannot convert 'student [rowNum][columnNum]' to 'student**' in assignment
a->seat = students;
^
is wrong because here you are assigning a 2d array to a double pointer. 2d array decayed into struct student (*)[] and then you tried to assign it to struct student **.
Instead you should create the jagged array yourself and work with it.
a->seat = malloc(sizeof(struct student*)* rowNum);
if(!a->seat){
perror("malloc");
exit(EXIT_FAILURE);
}
for(int i = 0; i< rowNum; i++){
a->seat[i] = malloc(sizeof(struct student)* columnNum);
if(!a->seat[i]){
perror("malloc");
exit(EXIT_FAILURE);
}
}
After that you can pass the address of each struct student instance like you did and make changes to it.
To clarify further about the organization that you are likely to follow
struct seating room; Here room is a structure instance containing a double pointer. That's it. That pointer points to no where significant. It contains indeterminate value (garbage value).
Now you want to allocate some memory and work with it. That is being done in the function seating. As it is just a pointer, you allocate memory of rowNum struct student * and why struct student*? Because that in turn will point to a series of struct student variable instance.
After successful allocation, now you have the memory and it is not of automatic storage duration - it will stay when the function seating ends also. It's storage duration extends beyond the scope of the function.
Notice one thing, strcpy(s->last_name,"***"); but there is no last_name variable in the structure definition. It would be last. Same goes with other member variable also.
After making the changes you would pass the instance of struct student like this:-
for(int rows = 0; rows < rowNum; rows++){
for(int columns = 0; columns < columnNum; columns++){
student_init_default(&a->seat[rows][columns]);
}
}
You are trying to assign to a->seat something that does not fit(not possible). But even if it would fit it would be wrong as struct student students[rowNum][columnNum]; is defined locally to the function seating(), so the moment the code returned from this function all memory a->seat pointed to would have become invalid. Accessing it would be undefined behavior then. (alk pointed this).

Auto Generating Structure Member Names in C

I've recently been introduced to struct and in experimenting, I encountered a problem that I can't seem to find a solution for.
I want to create a structure with several members but I want the names for each member to be automatically generated to avoid tedious process of doing this manually. So far I have my structure and a function which I want to use to create a member.
STRUCT
struct Customers
{
char name[30];
int age;
}
PROTOTYPE
void newCustomer(Customers *Customer);
FUNCTION
void newCustomer(Customers *Customer)
{
char gender;
int age;
scanf_s("%c", 1, &gender);
scanf_s("%d", &age);
Customer->gender = gender;
Customer->age = age;
}
MAIN
int main()
{
int noOfCustomers;
int i = 0;
printf("How many customers will you be entering? : ");
scanf_s("%d", &noOfCustomers);
for(i = 0; i < noOfCustomers; i++)
{
Customers i;
newCustomer(&i);
}
return 0;
}
Basically I want to do something like this... where each member is automatically represented by an ID or number. I do understand that the above example won't work because i is being declared locally within the loop as a sructure member and not an int but I want to know if there is a method of achieving this.
Thanks in advance for any help :)
You can use static integer variable, call itoa to convert it to string, and then, increment.

Do I need to create three separate arrays for my assignment?

Ok firstly I'll explain my assignment. For this assignment I have to use dynamic memory allocation which I am having no problems with. What I am having a problem with is figuring out the correct way to work my assignment. For my assignment I need to create a program that prompt the user to enter how many students they have then ask for the following information; Student ID, Birthdate, and Phone number. I need to use a loop to prompt the user to enter all the students information. I need to create a loop that will scan through all the student IDs and find the oldest student using their birthdate (The loop must be able scan through more then 3 students).
Here is my code, I havent done much in it yet because I'm not sure really where to start. I've already setup the dynamic memory allocation, but I don't know how to work the rest of this. Please help me.
Thank you.
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int * studentData= NULL;
int students;
printf("How many students are you entering records for:\n");
scanf("%d", &students);
studentData=(int*)malloc((sizeof(int)*students));
}
You could define a structure:
//Define a type, such as int, char, double...
typedef struct studentDataType {
int ID;
int birthDateDay;
int birthDateMonth;
int birthDateYear;
int phoneNumber;
};
Then create an array, where each of those elements is of type studentData:
//Create an array, where each element is of type studentData
studentDataType *studentData = (studentDataType *)malloc(numberOfStudents * sizeof(studentData));
Then loop through them with:
for (int i = 0 ; i < numberOfStudents ; ++i) {
printf("%i %i %i\n", studentData[i].ID, studentData[i].phoneNumber);
}
Use the following struct. You can make year, month and day as separate fields. It will be simpler for a quick start:
struct Student
{
int studentID;
int year;
int month;
int day;
long long phone; // phone is too large for 32 int
};

Resources