Two dimensional array of string in struct-C - c

I am trying to make a two dimensional array in a struct using pointer since I am new to c and get quite confuse in the topic of pointer. Help please!
struct course
{
char *coursecode;
char *coursesession[5];
};
int main()
{
int n = 0;
int numSession = 0;
struct course *main = malloc(sizeof(struct course));
printf("Enter the course code and the session in this order:");
scanf("%s", main->coursecode);
printf("Enter the number of session required:");
scanf("%d", &numSession);
for (int i = 0; i < numSession; ++i)
{
printf("Enter the session code (M1...):");
scanf("%s", main->coursesession[i]);
}
++n;
}

You've declared coursecode to be a pointer to char, but you need to allocate space for it, which you can do with malloc.
And you've declared coursesession to be an array of 5 pointers to char. You need to allocate space for all 5 pointers, again with malloc.
Alternatively, you could declare both of them as arrays, e.g.
struct course
{
char coursecode[100];
char coursesession[5][100];
};
This declares coursecode to be an array of 100 char, and coursesession to be an array of 5 arrays of 100 char. Obviously you could adjust the 100 to whatever you need, but the storage size would be fixed regardless.

You can modify code like this
#include <stdio.h>
#include<stdlib.h>
struct course
{
char *coursecode;
char *coursesession[5];
};
int main()
{
int n,i = 0;
int numSession = 0;
struct course main;
main.coursecode = (char *)malloc(100*sizeof(char));
printf("Enter the course code and the session in this order:");
scanf("%s", main.coursecode);
printf("Enter the number of session required:");
scanf("%d", &numSession);
for (i = 0; i < numSession; ++i)
{
printf("Enter the session code (M1...):");
main.coursesession[i] = (char *)malloc(100*sizeof(char));
scanf("%s", main.coursesession[i]);
}
++n;
free(main.coursecode);
for (i = 0; i < numSession; ++i){
free(main.coursesession[i]);
}
}

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.

Passing Pointers to Pointers into Functions in C

I'm working on a class project and I'm still learning C.
The goal is to ask the user how many items are available for sale today, and then ask them to enter those items one-by-one to new lines, and have them be entered into an array of strings.
Then print the array as a list to show the available items.
We cannot use statically declared arrays, and must use only pointers.
The functions here are required. I am required to have the get_items() function modify the array rather than return a result.
I'm having a lot of trouble making get_items() work. Anything I try either ends up with "exited, segmentation fault" or printing (NULL) when I go to print the items of the array.
Any suggestions to make this work would be greatly appreciated.
char* get_item() {
char *item = calloc(61,sizeof(char));
scanf(" %[^\n]",item);
return item;
}
void get_items(char ***items, int *num_items){
int i;
printf("Enter the %d available items one to a line: \n",*num_items);
for(i = 0; i < *num_items; i++) {
**(items+i) = get_item();
}
}
int main(void) {
char **items=NULL; /* this is the pointer for the start of the ingredients array */
int num_items = -1,
int i;
printf("How many available items do we have today? ");
scanf("%d",&num_items);
items = calloc(num_items,sizeof(char*));
get_items(&items,&num_items);
printf("Available items today are: \n");
for(i = 0; i < num_items; i++) {
printf("%i. %s\n",i+1,*(items+i));
}
In get_items, **(items+i) should be *(*items+i) or (*items)[i].
However, get_items has too many levels of pointer dereferencing. The following is simpler:
void get_items(char **items, int num_items){
int i;
printf("Enter the %d available items one to a line: \n",num_items);
for(i = 0; i < num_items; i++) {
*(items+i) = get_item(); // or more readable: items[i] = get_item();
}
}
The call to get_items from main would then need to be changed to the following:
get_items(items,num_items);
The original prototype void get_items(char ***items, int *num_items) suggests that some of the code in main should have been done in get_items instead:
void get_items(char ***items, int *num_items){
int i;
printf("How many available items do we have today? ");
scanf("%d",num_items);
*items = calloc(*num_items,sizeof(char*));
printf("Enter the %d available items one to a line: \n",*num_items);
for(i = 0; i < *num_items; i++) {
*(*items+i) = get_item();
}
}
Then main can be reduced to the following:
int main(void) {
char **items=NULL; /* this is the pointer for the start of the ingredients array */
int num_items = -1,
int i;
get_items(&items,&num_items);
printf("Available items today are: \n");
for(i = 0; i < num_items; i++) {
printf("%i. %s\n",i+1,*(items+i));
}
}

How to Print an array with names

I wrote this code to input names to array (eg:Jon,raj...) and the input part is ok but how to print exact name that i input to this array a[5] why this code is not working
#include <stdlib.h>
#include<stdio.h>
int main(){
int i;
char a[5];
for(i=0;i<5;i++){
printf("Enter ");
scanf("%s",&a[i]);
}
for(i=0;i<5;i++){
printf("%s \n",a[i]);
}
}
Your array a is an array of chars. This means that in each position you will have only one char.
You can do this any one of these two ways:
Pre-allocated (array of arrays of chars)
#include <stdio.h>
int main(){
const int NAME_MAXIMUM_SIZE = 50;
const int NUMBER_OF_NAMES = 5;
int index;
char names [NUMBER_OF_NAMES][NAME_MAXIMUM_SIZE];
for(index=0; index<NUMBER_OF_NAMES; index++){
printf("Enter ");
scanf("%49s",names[index]);
}
for(index=0; index<NUMBER_OF_NAMES; index++){
printf("%s \n",names[index]);
}
}
Malloc + free (array of pointers)
#include <stdio.h>
#include <stdlib.h>
int main(){
const int NAME_MAXIMUM_SIZE = 50;
const int NUMBER_OF_NAMES = 5;
int index;
char *names [NUMBER_OF_NAMES];
for(index=0; index<NUMBER_OF_NAMES; index++){
names[index] = (char*)malloc(NAME_MAXIMUM_SIZE);
printf("Enter ");
scanf("%49s",names[index]);
}
for(index=0; index<NUMBER_OF_NAMES; index++){
printf("%s \n",names[index]);
free(names[index]);
}
}
You can make use of 2 dimensional array. Here your variable a which is a character array stores only one character at each index.
#include <stdlib.h>
#include<stdio.h>
int main(){
int i;
char a[5];
for(i=0;i<5;i++){
printf("Enter ");
scanf("%s",&a[i]);
}
for(i=0;i<5;i++){
printf("%s \n",a[i]);
}
}
"...wrote this code to input names to array..."
char a[5] does not create 5 C strings. It is simply an array of 5 char. It provides room for only 1, 4 character C string (leaving room for the \0 terminator). If you need an array of names, of typical size the code will need an array of arrays each with space sufficient for typical names. For example:
char a[5][80] = {{0}}; //provides an array capable of containing 5 names
Also, in the read statement: scanf("%s",&a[i]);, the format code %s is expecting to process an array of char. But is provided with &a[i] which is only a single character. If you are going to use scanf, then call it like this: scanf("%s",a); Same issue with the print statement.
Make the following edits to address these basic issues:
int main(void)
{
int i = 0;
char a[5][80] = {{0}};//space for 5 names, each with up to 79 characters
//arrays are initialized to zeros
for(i=0;i<sizeof(a)/sizeof(a[0]);i++)//sizeof(a)/sizeof(a[0]) is flexible way to
//loop only through number of names.
//If array size changes, expression will still work
{
printf("Enter name %d:\n ", i+1);
scanf("%79s",a[i]);//limit input to prevent overflow
// ^^
}
for(i=0;i<sizeof(a[0])/sizeof(a[0][0]);i++)
{
printf("%s \n",a[i]);
}
return 0;
}

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

How to correctly allocate memory for an array of structs in C?

This is the first time I'm using structs as I am still relatively new to C. When I try to input values for 3 structs the program crashes, but it works fine for 1 and 2. I think I may not actually be allocating enough memory. Is this the correct way to allocate memory for an array of structs?
#include <stdio.h>
#include <stdlib.h>
#define MIN_SIZE 0
#define MAX_SIZE 100
#define MAX_MONTH_STR 9
//Define a struct data type
typedef struct
{
char* month;
int day;
int year;
}date;
//Method to allocate memory for a list of date structures
date* allocateStruct(int size)
{
//Declaration of variables
date *array;
int i;
//Allocate memory for rows (to store 'size' many pointers to 'date' struct data type)
array = malloc(size*sizeof(date*));
//For-loop to allocate memory for columns (to store 'size' many integers, and initialize them to zero)
for (i=0; i<size; i++)
{
array[i].month = calloc(MAX_MONTH_STR,sizeof(char));
array[i].day = calloc(1,sizeof(int));
array[i].year = calloc(1,sizeof(int));
}
return array;
}
//Method to free memory allocated
//TO DO. . .
int main()
{
//Declaration of variables
int n;
date* date_list;
int i, j, k; //used in loops
//Read input
do
{
//printf("Enter number of dates you want to enter (between 1 and 10000):\n");
scanf("%d", &n);
}while(n<MIN_SIZE || n>MAX_SIZE);
//ALLOCATE MEMORY
date_list = allocateStruct(n);
//For-loop to store values in 'date_list'
for (i=0; i<n; i++)
{
//printf("Enter the date (month day year) in the following format: text number number");
scanf("%s", date_list[i].month);
scanf("%d", &date_list[i].day);
scanf("%d", &date_list[i].year); //need & ?
}
//--------> crashes here if 3 dates are input, ok for 1 and 2
//Test print
for (i=0; i<n; i++)
{
//printf("Enter the date (month day year) in the following format: text number number");
printf("%s ", date_list[i].month);
printf("%d ", date_list[i].day);
printf("%d\n", date_list[i].year); //need & ?
}
return 0;
}
You are trying to allocate a array with the size of the pointer to the date struct instead of the actual size of the date struct.
Change date* to date:
array = malloc(size*sizeof(date));
Furthermore you don't need to allocate the day and year variables, because the malloc allocates them for you.
for (i=0; i<size; i++)
{
array[i].month = calloc(MAX_MONTH_STR,sizeof(char));
array[i].day = 0;
array[i].year = 0;
}

Resources