I seem to not be able to find the problem to make the program work. C is telling me "error: Invalid operands to binary != 'grocerylist' (aka struct grocerylist) and 'int' When i try to solve this problem other bugs pop out, can anyone see other problems in this code except for the bug I posted about?
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
typedef struct grocerylist
{
char name[MAX];
float ammount;
char unit[MAX];
} grocerylist;
struct grocerylist * enterItems(int arr)
{
grocerylist * itemtolist;
itemtolist = (grocerylist*)malloc(sizeof(grocerylist)*arr);
if (*itemtolist != 0)
{
int i;
for(i = 0; i < arr; i++)
{
printf("Enter item name: /n");
scanf("%c", (itemtolist[i]).name);
printf("Enter ammount of item: /n");
scanf("%f", &(itemtolist[i]).ammount);
printf("Enter unit of item: /n");
scanf("%c", (itemtolist[i]).unit);
}
}
return itemtolist;
}
void printShoppingList(grocerylist *itemtolist, int arr)
{
int i;
for (i = 0; i < arr; i++)
{
printf("%s, %f, %s", itemtolist[i].name, itemtolist[i].ammount,
itemtolist[i].unit);
}
}
int main(void)
{
int arr, number;
grocerylist * itemtolist;
while (number == 0)
{
printf("How many items would you like to add to your list? /n");
scanf("%i", &arr);
itemtolist = enterItems(arr);
printShoppingList(itemtolist, arr);
free(itemtolist);
printf("Do you want to enter another item. 0 for yes, 1 for no");
scanf("%i", &number);
}
return 0;
}
You want to check that itemtolist itself (a pointer) isn't a null pointer.
But instead, your code attempts to compare *itemtolist (the pointed-at list), which isn't comparable to 0.
This fragment should be improved:
grocerylist * itemtolist;
itemtolist = (grocerylist*)malloc(sizeof(grocerylist)*arr);
if (*itemtolist != 0)
I'd write this as:
grocerylist *itemtolist = malloc((sizeof *itemtolist) * arr);
if (itemtolist)
Notes:
itemtolist != 0 is equivalent to just itemlist here in a boolean context. You can write it the long way if you want, but the short form is probably more idiomatic in C.
We don't cast the result of any of the malloc() family of functions.
Use the sizeof operator on the *itemlist so it automatically uses the correct type.
Initialize the variable as you declare it - that helps avoid accidentally using unintialized variables (but your compiler warnings should include that).
Also note that you really ought to check the return value from scanf() - I assume you removed the checking to make your example short for the question. You will need to change %c to %99s, but again, compiling with gcc -Wall or equivalent will help you spot that.
Related
I am trying to access different elements in my dynamic struct array however I can't seem to access any other element in the array besides the first.
C file
#include <stdio.h>
#include <stdlib.h>
#include "tuples.h"
void createTuple();
int main() {
createTuple();
return 0;
}
void createTuple(){
int numOfTup;
printf("How many tuples would you like to create:\n");
scanf(" %d", &numOfTup);
tuple_t *tuples;
tuples = malloc(numOfTup * sizeof(char) * sizeof(int) * 3);
if (tuples == NULL){
printf("Memory allocation failed");
exit(EXIT_FAILURE);
}
for (int j = 0; j < numOfTup; ++j) {
printf("Enter an identifier for the Tuple: \n");
scanf(" %c", &tuples[j].identifier);
printf("TUPLE: %c\n",tuples[j].identifier);
for (int i = 0; i < 4; ++i) {
printf("Enter the value for the tuple (C:I:I:I)\n");
if (i == 0) {
scanf(" %c", &tuples[j].val0);
} else if (i == 1) {
scanf(" %d", &tuples[j].val1);
} else if (i == 2) {
scanf(" %d", &tuples[j].val2);
} else if (i == 3) {
scanf(" %d", &tuples[j].val3);
}
}
}
}
Header file for the struct
#ifndef TASK2_TUPLES_H
#define TASK2_TUPLES_H
struct tuple{
char identifier[100];
char val0;
int val1;
int val2;
int val3;
};
typedef struct tuple tuple_t;
#endif //TASK2_TUPLES_H
I can't seem to access the struct at tuples[j] because whenever I try to run it it only saves the first set of elements.
Also whenever inputting the identifier the compiler skips the loop and does not allow me to enter any elements into the struct.
Thanks.
For starters, the statement:
tuples = malloc(numOfTup * sizeof(char) * sizeof(int) * 3);
//always ==1 why? why?
Should look more like:
tuples = malloc(numOfTup * sizeof(*tuples));
and:
scanf(" %c", &tuples[j].identifier);//wrong format specifier for string
^^^ ^ //and address of ( & ) operator not needed for string.
Should be:
scanf("%s", tuples[j].identifier);
^^ ^
There are several issues with your code:
You allocate nowhere near enough memory. If your tuple identifier is 100 chars, you should allocate at least 101 * sizeof(char) + 3*sizeof(int) bytes of memory. In practice, this might not suffice because the compiler might pad the struct to better align with memory. Thus, the real size might be greater. The safe thing to do is to allocate sizeof(tuple_t) bytes
Your scanf function to read the identifier reads a char, not a string. use %s to read string. Also, scanf expects pointers to already allocated objects of the type specified by their corresponding format specifier, in our case, %s is a string, so the type should be char *. Thus, the parameter should be tuples[j].identifier, rather than &tuples[j].identifier
Overall:
#include <stdio.h>
#include <stdlib.h>
#include "tuples.h"
void createTuple();
int main() {
createTuple();
return 0;
}
void createTuple(){
int numOfTup;
printf("How many tuples would you like to create:\n");
scanf(" %d", &numOfTup);
tuple_t *tuples;
tuples = malloc(numOfTup * sizeof(tuple_t));
if (tuples == NULL){
printf("Memory allocation failed");
exit(EXIT_FAILURE);
}
for (int j = 0; j < numOfTup; ++j) {
printf("Enter an identifier for the Tuple: \n");
scanf("%s", tuples[j].identifier);
printf("TUPLE: %s\n",tuples[j].identifier);
for (int i = 0; i < 4; ++i) {
printf("Enter the value for the tuple (C:I:I:I)\n");
if (i == 0) {
scanf(" %c", &tuples[j].val0);
} else if (i == 1) {
scanf(" %d", &tuples[j].val1);
} else if (i == 2) {
scanf(" %d", &tuples[j].val2);
} else if (i == 3) {
scanf(" %d", &tuples[j].val3);
}
}
}
}
in this program I try to sort customer savings descendingly. And I've tried to compile the code. And I'm still not to understand about pointer. There is an error with message "Assignment to expression with array type error". The target output of this program is tend to be the sorted customers(with their names, and account numbers). I've search in the internet about that error. But I still don't get the solution. Can someone help me to solve the error? Thanks.
#include <stdio.h>
#include <stdlib.h>
struct Data
{
long long int Savings[100], AccNo[100];
char Name[100];
};
int main ()
{
struct Data *ptr;
int n, i, j, swap = 1, x, y;
long long int max, min, temp;
printf ("Enter number of customer(s) : ");
scanf ("%d", &n);
ptr = (struct Data *) malloc (n * sizeof (struct Data));
for (i = 0; i < n; i++)
{
printf ("Enter customer %d", i + 1);
printf ("\nName : ");
getchar ();
scanf ("%[^\n]s", &(ptr + i)->Name);
printf ("Savings : ");
scanf ("%d", &(ptr + i)->Savings);
printf ("Account Number : ");
scanf ("%d", &(ptr + i)->AccNo);
printf ("\n");
}
//Sorting bubblesort
for (x = 0; x < n; x++)
{
for (y = 0; y < (n - x - 1); y++)
{
if ((ptr + y)->Savings > (ptr + y + 1)->Savings)
{
temp = (ptr + y)->Savings;
(ptr + y)->Savings = (ptr + y + 1)->Savings;
(ptr + y + 1)->Savings = temp;
}
}
}
//Print sorted
printf ("\n Sorted customers are (:\n");
for (i = 0; i < n; ++i)
{
printf ("%s\n", (ptr + i)->Name);
printf ("%d\n", (ptr + i)->Savings);
}
free (ptr);
return 0;
}
You need to compile your code with warnings enabled, the will guide
you through debugging step by step. Try to eliminate one, and
compile again. In GCC for example, you would use -Wall flag.
The numerical fields of your struct should be just numbers, not
arrays. Moreover, having their type as long long int seems a bit
too much, but I leave that on you.
Having (ptr + y)->Savings to access the y-th element of an array
of structs and the its field names Savings is technically correct,
but it's much more cleaner (thus increases readability and
maintainability) to write ptr[y].Savings. That is a general rule,
applying to the rest of your code.
I believe the above led you to make two syntactical errors when you
were reading the numerical data of the customers with scanf(),
since you know that an integer in general needs the & operator. If
you had used the clean approach from the start, you wouldn't made
those, I believe.
For long long int use the %lld format specifier, not just %d.
In Bubblesort, when you find elements that need to be swapped, then
swap the whole elements, not just their Savingss. I recommend
creating a function to do that.
scanf("%[^\n]s" doesn't make much sense, I would change it to
scanf("%99s", where 99 is the maximum size of your string, minus
one. Read more in the 2nd paragraph in scanf(“%[^\n]s”,a) question.
Putting everything together, we get:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Data {
long long int Savings, AccNo; // these should be numbers, not arrays
char Name[100];
};
void swap(struct Data* a, struct Data* b) {
struct Data tmp;
tmp.Savings = a->Savings;
tmp.AccNo = a->AccNo;
strcpy(tmp.Name, a->Name);
a->Savings = b->Savings;
a->AccNo = b->AccNo;
strcpy(a->Name, b->Name);
b->Savings = tmp.Savings;
b->AccNo = tmp.AccNo;
strcpy(b->Name, tmp.Name);
}
int main() {
struct Data *ptr;
int n, i, x, y;
printf("Enter number of customer(s) : ");
scanf("%d", &n);
ptr = malloc (n * sizeof(struct Data)); // do not cast malloc
for(i=0; i<n; i++) {
printf("Enter customer %d", i+1);
printf("\nName : ");
getchar();
scanf("%99s", ptr[i].Name); // ptr is a pointer, but now you want to actually use it as an array, so use '.'
printf("Savings : ");
scanf("%lld", &ptr[i].Savings); // needs &, just like you did for 'n'. USe `%lld' for long lont int as the format specifier.
printf("Account Number : ");
scanf("%lld", &ptr[i].AccNo); // needs &, just like you did for 'n'. USe `%lld' for long lont int as the format specifier.
printf("\n");
}
//Sorting bubblesort
for (x = 0; x < n; x++)
{
for (y = 0; y < n - x - 1; y++) // you don't need paranetheses in the stop condition
{
if (ptr[y].Savings > ptr[y + 1].Savings)
{
swap(&ptr[y], &ptr[y + 1]); // swap the whole element, not just its savings
}
}
}
//Print sorted
printf("\nSorted customers are:\n");
for(i=0; i<n; ++i)
{
printf("%s\n", (ptr+i)->Name);
printf("%lld\n", (ptr+i)->Savings);
}
free(ptr);
return 0;
}
Output (with relevant input):
Sorted customers are:
George
1
Babis
3
Theodor
20
PS: Do I cast the result of malloc? No!
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;
}
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.