I am trying to create a simple c program having an array of structures and I am passing each element of the array into a function and then trying to display it below is my code.
#include<stdio.h>
#include<string.h>
struct students{
char name[50];
int marks;
}st[10];
int size;
int addStudent(struct students st,char sname[], int marks){
static int count = 0;
strncpy(st.name,sname,strlen(sname));
st.marks = marks;
count++;
return count;
}
void showStudents(int size){
int i;
printf("Total number of students : %d\n",size);
for(i=0;i<size;i++){
printf("Student Name : %s\nMarks : %d\n",st[i].name,st[i].marks);
}
}
int main(){
int n, marks, i;
char name[50];
printf("Enter the total number of students : ");
scanf("%d",&n);
getchar();
for(i=0;i<n;i++){
printf("Enter the name of the Student : ");
fgets(name,50,stdin);
printf("Enter the marks of the student : ");
scanf("%d",&marks);
getchar();
size = addStudent(st[i], name, marks);
}
showStudents(size);
return 0;
}
and I am getting the following output
Enter the total number of students : 2
Enter the name of the Student : shibli
Enter the marks of the student : 23
Enter the name of the Student : max
Enter the marks of the student : 45
Total number of students : 2
Student Name :
Marks : 0
Student Name :
Marks : 0
Instead of getting the names and the marks I am getting no values can anyone help me what I am doing wrong with my code.
When passing a struct to a function, the function actually copies the struct to the input struct parameter and works on it. So the function addStudent did not work on your global array item but on a local copy.
You should pass a pointer to the struct item to the function and work on that. The code then looks like this:
int addStudent(struct students *st,char sname[], int marks){
static int count = 0;
strncpy(st->name,sname,strlen(sname)+1);
st->marks = marks;
count++;
return count;
}
and the call to the function addStudent looks like this:
size = addStudent(&st[i], name, marks);
In general the code can have other improvements like not using global variables, and static counters, but this is outside the scope of your question.
there is another issue here, using strncpy for copying strlen of string, does not end the string with null. So you should use strlen+1 to copy also the null termination, or simply use snprintf which adds null termination at end of string
Related
I have written a code for a ticket reservation halfway and I'm doubtful about the way i have used structures and arrays in my code. This code is not formatted properly because I am trying to see if this method of declaring "Bill" type variable will work or is this wrong?
the code gets compiled and runs successfully but I am doubtful whether my method is correct. Can anyone help? I just want to know whether the way I have declared structure type variables and used it is correct?Especially the last printf statement where I calculate the Amount.
#include<stdio.h>
#include<string.h>
#define SIZE 3
typedef struct
{
int billno;
char name[20];
char cat[20];
int type;
int range[3];
int tickets;
int class[3];
float price;
}Bill;
int main()
{
Bill array[3];
Bill d;
int input;
array[0].billno=6434;
strcpy(array[0].name,"Nimal");
strcpy(array[0].cat,"General");
array[0].type=1;
array[0].range[0]= 250;
array[0].range[1]= 0;
array[0].range[2]= 0;
array[0].price = 200;
array[1].billno=6065;
strcpy(array[1].name,"Kamal");
strcpy(array[1].cat,"Industrial");
array[1].type=2;
array[1].range[0]=622;
array[1].range[1]=1999;
array[1].range[2]=102;
array[1].price =125.60;
array[2].billno=7067;
strcpy(array[2].name,"Gayani");
strcpy(array[2].cat,"General");
array[2].type=2;
array[2].range[0]=220;
array[2].range[1]=350;
array[2].range[2]=10;
array[2].price = 86.90;
printf("****Main Menu****");
printf("1.Reserve a ticket:");
scanf("%d",&input);
if(input == 1)
{
printf("Enter your name: ");
scanf("%s", d.name);
printf("Enter the number of tickets you want");
scanf("%d",&d.tickets);
printf("Enter the number of tickets from first class");
scanf("%d",&d.class[0]);
printf("Enter the number of tcikets from second class");
scanf("%d",&d.class[1]);
printf("Enter the number of tickets from third class");
scanf("%d",&d.class[2]);
}
printf("\nReserve a ticket");
printf("\nName : %s",d.name);
printf("\nTickets from first class : %d",d.class[0]);
printf("Tickets from second class : %d\n",d.class[1]);
printf("Tickets from third class : %d\n",d.class[2]);
printf("\nConfirm the order? press Y if yes : ");
printf("Amount = %.2f ",d.class[0]*array[0].price+d.class[1]*array[1].price+d.class[2]*array[2].price);
return 0;
}
how do i correct this
i didn't use structure intentionally
this is a program to input student's name, subject and marks.
in the last block, the array (subject+f) 's 1st subscript is returning garbage values while the rest subscript are returning desired result.
i have also posted the image of output as link.
#include<stdio.h>
#include<string.h>
int main()
{
int size,i,k,sub,a=0,reference;
int temp,sorted;
char temp_s[10];
char temp_sb[10];
printf("enter the size of class\n");
scanf("%d",&size);
printf("how many subjects are there?\n");
scanf("%d",&sub);
reference = sub;
char name[size][20];
char subject[size*sub][20];
int marks[sub*size];
int total,subtotal,retotal;
for(k=0;k<sub;k++)
{
printf("so what's the no. %d subject\n",k+1);
scanf(" %s",(subject[k]));
}
for(i=0;i<size;i++)
{
int j,k=0;
printf("Enter a name of student %d\n",i+1);
scanf(" %s",(name+i));
for(j=a;j<reference;j++)
{
printf("enter marks of %s\n",(subject[k]));
scanf("%d",(marks+j));
k++;
}
a=j;
reference=sub+j;
}
reference=sub;
a=0;
printf("\n list of students and marks:\n");
for(i=0;i<size;i++)
{
int j,f=0;
printf("%s\n",(name+i));
for(j=a;j<reference;j++)
{
printf("%s %d\n",(subject[f]),(marks[j]));
f++;
}
a=j;
reference=sub+j;
}
}
Besides the problem with length of names and subjects, this here is a major problem:
(subject+k)
You are probably misunderstanding the subject[k] and *(subject + k) equivalent.
The variable subject is an array of arrays. That means subject[i] is an array (of char and can be used as a zero-terminated string).
The expression (subject + k) is a pointer to the array in subject[k]. It's equal to &subject[k] which have the type char (*)[10]. It's can not be used as a zero-terminated string without dereferencing. So either use *(subject + k) or the simple, less-to-write and easier-to-read subject[k].
I think you also need to change
int marks[sub];
to
int marks[size * sub];
one mark for each subject for each student, correct?
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;
}
I have a C program in which the user enters sets of grades. Everything works correctly. The GPA is calculated correctly, etc. However, when the numbers are printed back out, both pointers in the Student structs point to the same address for some reason, leading both students to display the grades of the second when the information is printed out. The rest of the information is correct, it's only the grades that are identical.
The only thing I can think of is that the second initialization of the grades array overwrites the first. I don't understand why this happens or how to fix it.
The following is sample IO of the program:
Enter the number of students:> 2
Enter the number of grades to track:> 3
There are 2 students.
There are 3 grades.
Enter information for student:
Enter SID:> 101
Enter last name:> Enright
Enter first name:> Reed
Enter grades (separated by space):> 70.1 60 92
Enter information for student:
Enter SID:> 123
Enter last name:> Claire
Enter first name:> Heidi
Enter grades (separated by space):> 82.5 96.1 89.0
Student ID #101:
Name: Reed Enright
Grades: 82.5 96.1 89.0
GPA: 74.03
Student ID #123:
Name: Heidi Claire
Grades: 82.5 96.1 89.0
GPA: 89.20
and this is the complete code:
#include <stdio.h>
#define NAME_SIZE 25
typedef struct {
int sid;
char last_name[NAME_SIZE];
char first_name[NAME_SIZE];
float *grades;
float gpa;
} Student;
// function prototypes
// get student information
Student prompt_student(int number_of_grades);
// calculate the gpa based on the grades
float calculate_gpa(Student student, int number_of_grades);
// prints all of the students
void print_all_students(Student students[], int number_of_students, int number_of_grades);
int main(){
// initialise variables
int number_of_students;
int number_of_grades;
// prompt for number of students
printf("\nEnter the number of students:> ");
scanf("%d", &number_of_students);
// prompt for number of grades
printf("Enter the number of grades to track:> ");
scanf("%d", &number_of_grades);
// confirm the above
printf("\nThere are %d students. \nThere are %d grades.\n",
number_of_students, number_of_grades);
// initialise student list
Student students[number_of_students];
// get and store student information
for(int i = 0; i < number_of_students; i++){
students[i] = prompt_student(number_of_grades);
}
// confirm the above
print_all_students(students, number_of_students, number_of_grades);
return 0;
}
Student prompt_student(int number_of_grades){
// initialise student variable
Student student;
float grades[number_of_grades];
printf("\nEnter information for student: \n");
// prompt for student info
printf("\tEnter SID:> ");
scanf("%d", &(student.sid));
printf("\tEnter last name:> ");
scanf("%s", student.last_name);
printf("\tEnter first name:> ");
scanf("%s", student.first_name);
printf("\tEnter grades (separated by space):> ");
for(int i = 0; i < number_of_grades; i++){
scanf("%f", &grades[i]);
}
student.grades = grades;
student.gpa = calculate_gpa(student, number_of_grades);
return student;
}
float calculate_gpa(Student student, int number_of_grades){
float total = 0; // initialise variable for sum of grades
// add all grades together
for(int i = 0; i < number_of_grades; i++){
total += student.grades[i];
}
// return average
return total / number_of_grades;
}
void print_all_students(Student students[], int number_of_students, int number_of_grades){
// loop through all students
for(int i = 0; i < number_of_students; i++){
// print student info
printf("\nStudent ID #%d:", students[i].sid);
printf("\n\tName:\t%s %s", students[i].first_name, students[i].last_name);
printf("\n\tGrades:\t");
for(int n = 0; n < number_of_grades; n++){
printf("%.1f ", students[i].grades[n]);
}
printf("\n\tGPA:\t%.2f", students[i].gpa);
}
printf("\n");
}
The problem is that inside function prompt_student you declared local array
float grades[number_of_grades];
and the address of the first element of this local array is assigned to data member grades of structure Student
student.grades = grades;
So this data member will always have the same address for each call of the function. And moreover the program has undefined behaviour because after exiting the function the local array is not alive. In general case it will be destroyed.
You must dynamically allocate an array and assign the address of the allocated array to data member grades.
For example
float *grades = malloc( number_of_grades * sizeof( float ) );
It is obvious that in main you should free the allocated memory when the corresponding object of the structure will not be used any more.
Problem :
In your prompt_student() function, grades is a local variable (array). It goes out of scope when you return from the function. So,, you cannot assign the array (base address) to student.grades and use it after the function returns. If you use the pointer to access the memory, it invokes undefined behaviour.
Solution:
You need to allocate memory using dynamic memory allocation malloc()/calloc() to student.grades and copy the scanned values in there. Dynamically allocated memory lifetime is untill they are freed and they have a global scope. So, untill you're freeing the memory by calling free(), you can use the memory from outside the prompt_student() function also.
You are using local ("on-stack") automatic variables that cease to exist when the scope they were declared in exits. This gives you undefined behavior.
You need to use dynamic memory allocation for this.
You're returning a local object which is gone after a return.
Student prompt_student(int number_of_grades){
// initialise student variable
Student student;
...
return student;
}
Instead, pass in a pointer to structure created outside the function scope
main() {
Student student;
prompt_student(&student, number_of_grades)
}
void prompt_student(Student *pStudent, int number_of_grades){
// initialise student variable
...
pStudent->grades = grades;
... etc ...
return;
}
I just finished to build my class-homework but when I run the code I get an error.
First error appears in line 52:
size = GetAndSetStd(x);
Then I press continue and the program keeps working until line number 88:
*x = (student *)malloc( size * sizeof(student) );
The final error I got it's this one:
Unhandled exception at 0x011f162b in Test01.exe: 0xC0000005: Access violation writing location 0xcccccccc.
As you can see I have allocated enough memory for it so I don't know what is the problem in the code.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
typedef struct{
int id;
char lname[16];
char fname[11];
unsigned a[3];
int flag;
}student;
int GetAndSetStd (student **x);
/*Function name:GetAndSetStd
Description : Function asks the user the number of students receiving data from the students.
Input: A double pointer to a student struct and size of the array
Output: size - size of the students in the array
Algorithm: First we get the size of the stuedents array from the user,Second Allocate memory for the array and by a for loop getting the info from the soruce text file..*/
void PrintArray (student *x,int size);
/*Function name:PrintArray
Description : The function prints the students on the screen array
Input: A pointer to a student struct and size of the array
Output: none
Algorithm: By a for loop the function prints the array of students.*/
student * MaxAvg(student *x,int size);
/*Function name:MaxAvg
Description : Students function accepts an array returns the address structure of the student with the highest average score.
Input: A pointer to a student struct and size of the array
Output: Address the structure of the student with the highest average score.
Algorithm: By a for loop the function calculates the avg score of the student and checks if it's higher than the next score .if it is higher it's save the index of the score and when the FOR loop is finished return the address of the index.*/
float StdAvg(student *x);
/*Function name:StdAvg
Description : The function gets a pointer to the student and calculate the grades average score.
Input: A pointer to a student in the struct
Output: returns the average grade score.
Algorithm: The function calculates the sum of the three grades of the student and then divide by the number of grades .the function returns the average score of the student.*/
void ChangeRandStd (student *x,int size);
/*Function name:ChangeRandStd
Description : The function gets the array of students and length of it, taking a random student and replaces the flag field value from 1 to 0.
Input: A pointer to a student struct and size of the array
Output: none
Algorithm: By DO WHILE loop, using rand function in the loop. we pick a random student and checks if the flag field is 1,unless keep searching for flag field value=1. after finding it change the value of flag field from 1 to 0.*/
int CopyToAnotherGroup (student *x,int size,student **arr);
void Get_Lost(char* str);
int main()
{ student **x,**y,*p,temp;
int size,n=1,len;
size=GetAndSetStd(x);
while(n)
{
printf("Press 1 to see all students\n");
printf("Press 2 to see two students with biggest average\n");
printf("Press 3 to change flag for random student\n");
printf("Press 4 to see all students from the new group\n");
printf("Press 0 to exit\n");
printf("enter your choise:");
scanf("%d",&n);
switch(n)
{
case 1: PrintArray(*x,size);break;
case 2: PrintArray(p=MaxAvg(*x,size),1);
temp=*p;
*p=*x[size-1];
*x[size-1]=temp;
PrintArray(MaxAvg(*x,size-1),1);
break;
case 3: ChangeRandStd(*x,size);
break;
case 4: len=CopyToAnotherGroup(*x,size,y);
PrintArray(*y,len);
}
}
free(*x);
free(*y);
system("pause");
return 0;
}
int GetAndSetStd (student **x)
{ int size,i;
FILE *f;
f=fopen("list.txt","r");
printf("Please enter the number of the students:");
scanf("%d",&size);
*x=(student *)malloc(size*sizeof(student));
if(!x)
Get_Lost("no memmory");
for (i=0 ; i<size ; i++)
{
fscanf(f,"%d%s%s%u%u%u",(*x)[i].id,(*x)[i].lname,(*x)[i].fname,(*x)[i].a[0],(*x)[i].a[1],(*x)[i].a[2]);
(*x)[i].flag=1;
}
fclose(f);
return size;
}
void PrintArray (student *x,int size)
{
int i;
for (i=0 ; i<size ; i++ )
{
printf("%d,%s,%s,%d,%d,%d,%d",x[i].id,x[i].lname,x[i].fname,x[i].flag,x[i].a[0],x[i].a[1],x[i].a[2]);
}
}
float StdAvg(student *x)
{
int sum=0;
float avg=0;
sum=(*x).a[0]+(*x).a[1]+(*x).a[2];
avg=sum/3.0;
return avg;
}
student * MaxAvg(student *x,int size)
{
float max_avg=StdAvg(x);
int i,index=0;
for(i=1 ; i<size ; i++ )
{
if(StdAvg(x+i)>max_avg)
{
max_avg=StdAvg(x+i);
index=i;
}
}
return x+i;
}
void ChangeRandStd (student *x,int size)
{
int temp;
do
{
temp=0+rand()%(size);
}while(x[temp].flag!=0);
x[temp].flag=0;
}
int CopyToAnotherGroup (student *x,int size,student **arr)
{
int i,count=0;
for ( i=0 ; i< size ; i++ )
{
if(x[i].flag==0)
{
count++;
*arr=(student*)realloc(arr,count*sizeof(student));
if(!*arr)
Get_Lost("no memmory");
(*arr)[count-1]=x[i];
}
}
return count;
}
void Get_Lost(char* str)
{
printf("\n%s",str);
exit(1);
}
Your problem is your declaration and usage of x in main(). You should be declaring a single-indirection pointer and passing its address instead:
student *x = NULL;
GetAndSetStd(&x);
And update the remainder of your code accordingly (which will be a lot of changes, but thats the price for writing this much code without seeing if it was actually correct incrementally). As-written you're passing a pointer value that is indeterminate and dereferencing for-write it within the called function. And before you ask, yes, y has similar problems.
The rest I leave to you (and Aniket has already pointed out your incorrect invocation of fscanf).
Like scanf, fscanf() also expects you to pass in the address of the variables to store the input data. You don't have it on the fscanf() line.. which can be the source of your segfault.
The error basically means that you are accessing a memory location that you are not authorized.
fscanf(f,"%d%s%s%u%u%u",(*x)[i].id,(*x)[i].lname,(*x)[i].fname,(*x)[i].a[0],(*x)[i].a[1],(*x)[i].a[2]);
should be:
fscanf(f,"%d%s%s%u%u%u",(*x)[i].id,(*x)[i].lname,(*x)[i].fname,&((*x)[i].a[0]),&((*x)[i].a[1]),&((*x)[i].a[2])));
Thanks for you help guys.
WhozCraig:
I have to send a double pointer to some of the functions not a single pointer.This is what our teacher ask for :|