Accessing and inputting elements into a dynamic array of structs in C - c

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);
}
}
}
}

Related

Issues with printing structs in C

I'm incredibly new to this and have a school assignment I have to write a gradebook program that uses a custom struct to hold student IDs and grades. I have been trying unsuccessfully for days to figure out why it will not print properly, or when it does print (after a lot of shifting things around) it only prints the second set of input.
The gradebook.h section is the custom structure.
// gradebook.h
struct gradeID
{
int id;
char grades[25];
};
// Gradebook.h is a header file to define
// a global structure.
#include "gradebook.h"
#include <stdio.h>
#include <stdlib.h>
void sort(struct gradeID *, int);
int main(void)
{
// Variables and structure definitions
int ctr;
char contInput;
int i;
struct gradeID grade;
struct gradeID *identifier;
int *temps;
// Allocates 10 integers worth of memory for the program to use.
// If there is not enough memory, the program will print an error
// statement and terminate the program.
temps = (int *) malloc(10 * sizeof(int));
if (temps == 0)
{
printf("Not enough memory!\n");
exit(1);
}
// Prints basic instructions for the program
printf("\t\tGradebook Recorder\n");
printf("Input student IDs and grades.\n");
printf("These will be sorted by ID and printed.\n");
/* Creates a for loop that will continue until the program
hits the designated number of array elements. For the sake
of expediency, I have set this amount to 10, but it can be
changed as necessary.*/
for(i = 0; i < 10; i++)
{
printf("Input student ID:\n");
scanf(" %d", &grade.id);
printf("Input grade:\n");
scanf(" %s", grade.grades);
// This allows early exit of the program
printf("Do you have more grades to enter?\n");
printf("Y/N\n");
scanf(" %c", &contInput);
if(contInput == 'N' || contInput == 'n')
{
printf("Finalizing and printing input-\n\n");
break;
}
ctr++;
}
printf("Grades Sorted by Student ID:\n\n");
printf("\tStudent ID: Student Grade: \n");
for(i = 0; i < ctr; i++)
{
printf("\t%d", grade.id );
printf("\t%s", grade.grades);
}
identifier[i] = grade;
return(0);
free(temps);
}
void sort(struct gradeID identifier[], int counter)
{
int inner;
int outer;
struct gradeID temp;
// Loops for sorting
for(outer = 0; outer < counter - 1; ++outer)
{
for(inner = outer + 1; inner < counter; ++inner)
{
if(identifier[inner].id < identifier[outer].id)
{
temp = identifier[inner];
identifier[inner] = identifier[outer];
identifier[outer] = temp;
}
}
}
return;
}
The pointer identifier is uninitialized
struct gradeID *identifier;
So this statement
identifier[i] = grade;
independent on the value of i invokes undefined behavior.
In this for loop
for(i = 0; i < 10; i++)
{
printf("Input student ID:\n");
scanf(" %d", &grade.id);
printf("Input grade:\n");
scanf(" %s", grade.grades);
// This allows early exit of the program
printf("Do you have more grades to enter?\n");
printf("Y/N\n");
scanf(" %c", &contInput);
if(contInput == 'N' || contInput == 'n')
{
printf("Finalizing and printing input-\n\n");
break;
}
ctr++;
}
you are entering new data in the same object grade of the structure type. So the new data overrides the previous data stored in the object.
Moreover the variable ctr was not initialized
int ctr;
So this statement in the above for loop
ctr++;
also invokes undefined behavior.
The variable temps that points to a dynamically allocated array
temps = (int *) malloc(10 * sizeof(int));
is not used.
This statement
free(temps);
never gets the control because before it there is the return statement
return(0);
free(temps);
What you need is to define an array of the type struct gradeID as for example
struct gradeID grades[10];
and fill it with values.

Assignment to expression with array type error

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!

C - "Error: Invalid operands to binary != ..."

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.

Stack around the variable was corrupted with pointer arithmetics

With the code below, I'd always run into "Stack around the variable 'UserCode' was corrupted.
If I'm not mistaken, when I do userCode = (char*)malloc(sizeof(char)*N);, shouldn't it create an "array" with size of char*n ? I'm guessing my issue is either with my declaration of an array, or my pointer arithmetic.
Any help would be highly appreciated.
#include "stdafx.h"
#include <math.h>
int userPrompt1() {
int numOfAlphabets = 0;
printf("Please enter a number from 1 to 8 to choose how many alphabets you want\n");
scanf_s(" %d", &numOfAlphabets);
if (numOfAlphabets > 8 || numOfAlphabets < 0) {
printf("Sorry! Invalid number entered. Try again. \n");
numOfAlphabets = userPrompt1();
}
return numOfAlphabets;
}
int userPrompt2() {
int numOfLetters = 0;
printf("Please enter the number of letters you want to guess\n");
scanf_s(" %d", &numOfLetters);
if (numOfLetters < 0) {
printf("Sorry! Invalid number entered. Try again. \n");
numOfLetters = userPrompt2;
}
return numOfLetters;
}
int tryCalculator(int K, int N) {
int tries = 0;
tries = 1 + ceil(N * log2(K));
return tries;
}
void codeGenerator(char codeGuessIn[], char letters[], int size) {
for (int i = 0; i < size; i++) {
int rando = rand() % size;
codeGuessIn[i] = letters[rando];
printf(" %c", codeGuessIn[i]);
}
printf("\n");
}
void codeChecker(char codeGuessIn[], char generatedCode[], int size) {
int correctAlphabets = 0;
for (int i = 0; i < size; i++) {
if (codeGuessIn[i] == generatedCode[i]) {
correctAlphabets++;
}
}
printf(" %d in correct place \n", correctAlphabets);
}
void getUserCode(int size, char *userCode[]) {
for (int i = 0; i < size; i++) {
printf("Please enter letter #%d \n", i+1);
getchar();
scanf_s(" %c", &userCode[i]);
}
}
int main(void)
{
char letters[8] = { 'A','B','C','D','E','F','G','H' };
char *generatedCode; //array to hold generated code
char *userCode; // array to hold generated code.
int K = userPrompt1(); //how many different alphabets in code
int N = userPrompt2(); //how many letters in code
int tries = tryCalculator(K, N);
//int gameEnd = 1;
userCode = (char*)malloc(sizeof(char)*N);
generatedCode = (char*)malloc(sizeof(char)*N);
codeGenerator(generatedCode, letters, N);
getUserCode(N, &userCode);
//codeChecker(userCode, generatedCode, N);
return 0;
}
void getUserCode(int size, char *userCode[]) {
scanf_s(" %c", &userCode[i]);
Here, userCode[i] is a char * (pointer-to-char), &userCode[i] is a char ** (pointer-to-pointer-to-char), and scanf("%c") expects a char *. A good compiler would warn about that.
I think what you meant to do here is something like:
void getUserCode(int size, char *userCode) {
scanf_s(" %c", &userCode[i]);
}
int main(void) {
char *userCode = malloc(N);
getUserCode(N, userCode);
}
The printf(), getchar(), scanf() combination here reeks of the bad habits created by scanf: you're discarding the first character entered by the user because you're relying on an extra character in the input buffer.
See http://c-faq.com/stdio/scanfprobs.html and read full lines of input with fgets() instead of using scanf().
Also,
int userPrompt2() {
int numOfLetters = 0;
...
numOfLetters = userPrompt2;
}
You're assigning a function pointer to an int. (A normal compiler should warn about this.) If the idea here is to call the function again to repeat the prompt in case the user enters something silly, it's probably a better idea to use a loop instead of a recursive call anyway.

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;
}

Resources