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 :|
Related
I am stuck on a programming assignment in C. The user has to enter a number specifying the size of an array no bigger than 10 elements which will store the names of students. This must be done in a separate function from the main function called getNames. Each name can be up to 14 characters and getNames must be invoked from within the main function. Here is my code:
#include <stdio.h>
void getNames(char *a, int n){
int i;
for(i=0; i<n; i++){
printf("Enter a name: ");
scanf("%s", &a[i]);
}
}
void printNames(char *a, int n){
int i;
for(i=0; i<n; i++){
printf("%s\n", &a[i]);
}
}
void main(){
int num; //number of names in array 'names'
printf("Num of students: ");
scanf("%d", &num);
char names[num][15]; //each name is 14 characters plus
//a null character
getNames(names[num], num);
printNames(names[num], num);
}
The code compiles and runs without syntax errors but the array is not filled correctly. For example:
Num of students: 5
Enter a name: Jeb
Enter a name: Bob
Enter a name: Bill
Enter a name: Val
Enter a name: Matt
returns:
JBBVMatt
BBVMatt
BVMatt
VMatt
Matt
Clearly there is an issue writing to the array but I am not sure what it is.
For this assignment our professor was adamant that we cannot use any global variables. His wording was rather vague about how we should implement this. My first thought would be to move the for loop in getNames into the main function and just calling getNames repeatedly but I would like a solution that incorporates that into getNames. I'm new to C, having mostly dealt with Java so please bear with me. Any help would be appreciated.
If the code you have posted is exactly the code you are using, then it is invoking undefined behavior by accessing a memory location that your program does not own: getNames(names[num], num);.
Array indexing in C goes from 0 to n-1. (or from names[0]-names[num-1]) Same in other similar calls.
next issue is the function prototypes to accommodate;
char names[num][15];
The function needs to send the address of an array of arrays. See edits on code to show the difference.
Next issue are the following statements, see comments after each
getNames(names[num], num);//names[n] points to memory beyond what is owned.
//should point to address of beginning of memory &names[0]
printNames(names[num], num);//ditto
Working code example, see edits to explain:
//void getNames(char *a, int n){//change *a to either a[][15] or (*a)
void getNames(char a[][15], int n){
int i;
for(i=0; i<n; i++){
printf("Enter a name: ");
scanf("%s", a[i]);
}
}
//void printNames(char *a, int n){ //change *a to either a[][15] or (*a)
void printNames(char a[][15], int n){
int i;
for(i=0; i<n; i++){
printf("%s\n", a[i]);
}
}
void main(){
int num; //number of names in array 'names'
printf("Num of students: ");
scanf("%d", &num);
char names[num][15]; //each name is 14 characters plus
//a null character
//getNames(names[num], num);//names[n] points to memory beyond what is owned.
//printNames(names[num], num);//ditto
getNames(&names[0], num);
printNames(&names[0], num);
}
you can do following
Method
in main function call as below
getNames(names, num);
printNames(names, num);
and change the functions as below
void getNames(char (*a)[15], int n)
{
...
}
void printNames(char (*a)[15], int n)
{
...
}
Method , in main calls remain same
void getNames(char a[5][15], int n)
and
void printNames(char a[5][15], int n)
But instead of using hard values better to use #define row and col sizes
I tried to do with a variable like temp but it didnt work.
The points is that i want to pass the value of a component of an array(fail[f]) to another array(pass[p]) and fill that blank space with the last component of the same array(fail[f]) so i can print it in the end.
I tried with an example of grades: 2,4,3,5,6 and in the end it printed correctly for the first two averages, corectly for the final average of those who passed (because I did pass[*p]=5 as i knew from the exercise that the grades 4 will turn 5 and then passed it on the array pass[*p] whose size will enlarge max size 10).
The point is that in the end it printed the final average of the students who failed incorectlly because i was decreasing its size and printing him. That cause the digit -1 to appear as I had previously filled both arrays with -1.
To sum up I need somehow to remove each component fail[i]=4 from this array and move it to the end of array pass[i] as it is now equal to 5.
enter code here:
#include <stdio.h>
#include <stdlib.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
float average(int array[],int size);
int condition(int pass[],int *p,int fail[],int *f,int *fcounter,int *pcounter);
int main(int argc, char *argv[]) {
int i, pass[10],fail[10];
for(i=0;i<10;i++){
pass[i]=-1;
fail[i]=-1;
}
int end=0; `flag in case user wants to end`
int p=0,f=0,g=0; `g=counter for grades`
int grade;
do{
do{
printf("Enter grade (-1 if you want to end)\n");
scanf("%d",&grade);
if(grade==-1){
end=1;
}
else if(grade<0 || grade>10){
printf("Wrong input , grade must be between 0 and 10\n");
}
}while((grade<0 || grade>10) && end==0);
if(grade>=5){
pass[p]=grade;
p=p+1;
}
else if(grade>=0 && grade<5){
fail[f]=grade;
f=f+1;
}
g=g+1;
}while(g<10 && end==0);
float avg;
avg=average(pass,p);
printf("The average of the students who passed is:%f\n",avg);
avg=average(fail,f);
printf("The average of the students who failed is:%f\n",avg);
int fcounter,pcounter;
fcounter=f;
pcounter=p;
int esc=0;
while(fcounter>pcounter){
esc=condition(pass,&p,fail,&f,&fcounter,&pcounter);
if(esc==1){
pcounter=pcounter+999; /*so it gets out of the loop*/
}
avg=average(pass,p);
printf("The final average of the students who passed is:%f\n",avg);
avg=average(fail,f);
printf("The final average of the students who failed is:%f\n",avg);
printf("The grades of the students who passed are:");
for(i=0;i<p;i++){
printf("%d\t",pass[i]);
}
printf("\n");
printf("The grades of the students who failed are:");
for(i=0;i<f;i++){
printf("%d\t",fail[i]);
}
return 0;
}
float average(int array[],int size){
int i;
int sum=0;
float avrg;
for(i=0;i<size;i++){
sum=sum+array[i];
}
avrg=(float)sum/size;
return avrg;
}
int condition(int pass[],int *p,int fail[],int *f,int *fcounter,int *pcounter){
int i;
int esc=0;
int esc_counter=0;
for(i=0;i<*f;i++){
if(fail[i]==4){
fail[i]=fail[*f]; /*the problem is somewhere in these 6 lines i think*/
pass[*p]=5; /*i also tried to move element fail[i] to the last place of array
pass[*p] but still it didnt work and instead i did pass[*p]=5
cause i knew the outcome is always 5(it is asked on the
excersise*/
*f=*f-1;
*p=*p+1;
*fcounter=*fcounter-1;
*pcounter=*pcounter+1;
}
else if(fail[i]!=4){
esc_counter=esc_counter+1;
}
}
if(esc_counter=*f){
esc=1;
}
return esc;
}
I'm trying to write a program which includes an array that filled by user and find a value in it which specified by user then print if it found and count of that number in array.But it works only for first element of array.My code is below:
`void searchh(int arr[],int search,int number,int counter);
int main()
{
int number,search,i;
int counter=0;
printf("How many numbers will you enter?");
scanf("%d",&number);
int array[number];
for(i=0;i<number;i++){
printf("Please enter the %d. element of the array:",i+1);
scanf("%d",&array[i]);
}
printf("Please enter the number that you're looking for:");
scanf("%d",&search);
searchh(array,search,number,counter);
return 0;
}
void searchh(int arr[],int search,int number,int counter){
int i,c;
int key=search;
int num=number;
counter=0;
int arrsize=(int)(sizeof(arr)/sizeof(int));
int arrayent[(int)(sizeof(num)/sizeof(int))];
for(i=0;i<arrsize;i++)
{
if(arr[i]==key)
{
arrayent[counter]=i;
counter++;
}
}
printf("The number that you're looking for which is %d is found %d times.\nLocations:",key,counter);
if(counter>0){
for(c=0;c<sizeof(arrayent)/sizeof(int);c++){
printf("%d\n",arrayent[c]);
}
}
else
printf("Number doesn't exist!!");
}`
And Outputs:
Thanks for your helps.
int arrsize=(int)(sizeof(arr)/sizeof(int));
This already doesn't do what you think it does. sizeof(arr) - could be 4 if size of pointer is 4 bytes. In other words you can't check array size like that inside function, arr decays to pointer of first element of array. Hence sizeof(arr) will return size of pointer which could be 4 or 8. You need to pass the number of elements of the array to the function as parameter - which is number in your case.
This:
int arrayent[(int)(sizeof(num)/sizeof(int))];
is also strange. num is int. sizeof(num) and sizeof(int) will be same - and division will give you 1.
IMO these two lines
int arrsize=(int)(sizeof(arr)/sizeof(int));
int arrayent[(int)(sizeof(num)/sizeof(int))];
should just go as
int arrsize = number;
int arrayent[number];
PS. Also try to use a debugger to help you with some kind of issues.
I am a student trying to learn c coming from c++. I wrote the following code and it compiles fine; however, when I execute it I get an endless loop when calling the print function. I looked over the code and it seems to be valid to me, so why is it printing an endless loop?
#include <stdio.h>
#include <stdlib.h>
struct student
{
int id;
int score;
};
void generate(struct student *students, int n)
{
int randomId = rand () % n + 1;
int randomTestScore = rand() % 100 + 1;
students->id = randomId;
students->score = randomTestScore;
}
void sort(struct student *students, int n)
{
/*using insertion sort*/
for (unsigned int i = 1; i < n; ++i)
{
int next = students[i].score;
int j = i;
while(j > 0 && students[j-1].score > next)
{
students[j].score = students[j-1].score;
j--;
}
students[j].score = next;
}
}
void print(struct student *students, int n)
{
for (unsigned int i = 0; i < n; i++)
{
printf("Student at position No: %d Test Score: %d\n", i+1, students[i].score);
}
}
int main()
{
/*user enters num of students to create scores for*/
int num_students;
printf("Enter Num of students\n");
scanf("%d", num_students);
/*allocate memory for the amount of students user wants*/
struct student *userStudents = malloc(num_students*sizeof(struct student));
printf("Randomly filling students IDs & Test Scores...\n");
for (unsigned int i = 0; i < num_students; ++i)
{
generate(&userStudents[i], num_students);
}
printf("Array of students before sorting:\n");
print(userStudents, num_students);
printf("\nNow, sorting students by test scores...\n\n");
sort(userStudents, num_students);
printf("Array of students after sorting:\n");
print(userStudents, num_students);
return 0;
}
To use scanf() correctly it needs to alter the passed variable in place, and since there is no pass by refrence in c, you need to pass the address of the variable, so scanf() is able to modify it though a pointer, hence you need to use the & operator, but that is not enough.
The scanf() family of functions, return a value that must be checked before you can access the scanned values, you should never ignore that value, under any circumstances you should check for it.
What your code is doing is called undefined behavior, it's interpreting the passed integer as if it was a pointer, which is undefined behavior.
To prevent that you can activate compiler warnings, many compilers know what kind of parameter the *f functions expect, i.e. the functions which take a string as a format to be parsed and to allow the function to correctly grab the rest of the parameters passed via variable arguments to it.
The correct way to call scanf() in your program is
if (scanf("%d", &num_students) != 1)
return 1;
that is, from main() and hence it's ending the program, because you can't continue after that condition was true, in that case what actually happens is that num_students is not initialized, that would once again cause undefined behavior.
Change the call to scanf to:
/*
* correct way of calling scanf, passing the address of the wanted variable
*/
scanf("%d", &num_students);
^
This elliminates segmentation faults and makes the code runs OK on my machine.
I had a previous hint that you'd need to change your declaration of userStudents to a pointer to pointers, however I was incorrect. You are clearly correctly allocating enough contiguous memory to hold all of your structs pointed by *userStudents.
I'm working on a homework assignment and I've hit a brick wall. I think I have all of the code that I need, I just need to get the program to compile. The object of the assignment is
Create a structure to hold student names and averages. The structure should contain a first name, last name and an integer grade average.
Then:
Write a program that will do the following:
1.) Create an array of pointers to these student structures.
2.) Prompt the user for names and averages.
3.) After you get the student’s information use malloc to provide the memory to store the information.
4.) Place the address of the student, returned by malloc, into the pointer array.
5.) AFTER the user indicates there are no more students:
Search the data entered and find the highest and lowest grade
average.
a)Print the name and grade for the highest grade
b)Print the name and grade for the lowest grade
c)Print the average of all grades entered
Here is my code:
#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
#define SIZE 25
int enterStudents (int ePointArray[SIZE]);
void searchData (int *sPointArray, int *sHigh, int *sLow);
int calculateAvg (int, int *avgPointArray);
void printData (int, int *pHigh, int *pLow);
struct student
{
char firstName[20];
char lastName[20];
int average;
};
int main()
{
int pointArray[SIZE], high[3], low[3];
int i = 0, studentCounter, avgGrade;
for (i = 0; i < SIZE; i++)
pointArray[i] = 0;
studentCounter = enterStudents(pointArray);
searchData(pointArray, high, low);
avgGrade = calculateAvg(studentCounter, pointArray);
printData(avgGrade, high, low);
return 0;
}
int enterStudents (int ePointArray[SIZE])
{
char tempFname[20], tempLname[20], yesNo[2] = "y";
int tempAvg, counter = 0;
int *studPtr;
struct student aStud={"\0", "\0", 0};
while( counter < SIZE && strcmp(yesNo, "y")==0)
{
printf(" Enter first name: ");
scanf("%s", tempFname);
printf(" Enter last name: ");
scanf("%s", tempLname);
printf(" Enter grade average:");
scanf("%d", tempAvg);
strcpy(aStud.firstName, tempFname);
strcpy(aStud.lastName, tempLname);
aStud.average = tempAvg;
studPtr = malloc(sizeof(struct student));
ePointArray[counter] = *studPtr;
counter++;
printf("/n");
printf(" Do you have more students? yes or no:");
scanf("%s", yesNo);
}
return counter;
}
void searchData (int sPointArray[SIZE], int sHigh[3], int sLow[3])
{
int searchCounter = 0;
while( searchCounter = 0)
{
if( *sPointArray[searchCounter].average > *sPointArray[searchCounter+1].average)
{
sHigh[0] = &sPointArray[searchCounter].firstName;
sHigh[1] = &sPointArray[searchCounter].lastName;
sHigh[2] = &sPointArray[searchCounter].average;
}
if( *sPointArray[searchCounter].average < *sPointArray[searchCounter+1].average)
{
sLow[0] = &sPointArray[searchCounter].firstName;
sLow[1] = &sPointArray[searchCounter].lastName;
sLow[3] = &sPointArray[searchCounter].average;
}
searchCounter++;
}
}
int calculateAvg( int totalStudents, int avgPointArray[SIZE])
{
int sum = 0;
int avgCounter;
double overallAvg;
for( avgCounter = 0; avgCounter < totalStudents; avgCounter++)
sum = sum + *avgPointArray[avgCounter].average;
overallAvg = sum/totalStudents;
return overallAvg;
}
void printData (int pAverage, int pHigh[3], int pLow[3])
{
printf(" Highest Grade: %s %s %d", pHigh[0], pHigh[1], pHigh[3]);
printf("/n");
printf(" Lowest Grade: %s %s %d", pLow[0], pLow[2], pLow[3]);
printf("/n");
printf(" Average Grade: %d",pAverage);
}
The main chunk of problems come from the searchData function. In the if statements, every occurrence of *sPointArray and &sPointArray is underlined in red and the error reads
"Error: expression must have class type"
The same thing also happens in the calculateAvg function with *avgPointArray in the for loop. I know that the error is a fairly common problem for noobie C programmers (i.e myself) and that it generally has to do with writing the code as a function instead of a statement or something like that, but I can't for the life of me find where I have went wrong. Any help would be highly appreciated. I've been working at this for so long my vision is blurring.
Also, for anyone who solves this in like two seconds and wants proof that I'm a true idiot, there is an error in the enterStudents function where it says StudPtr = malloc(sizeof...). The error shows under the assignment symbol and says
"Error: a value of type "void*" cannot be assigned to an entity of type "int*".
I understand this concept in theory, but some advice for how to fix it would be highly appreciated.
Thank you in advance for any help.
You declare the sPointArray as an array of integers, but use it as an array of structures.