I have two fucntions that prompt the user to print ingredients names for pizza and print them out. But whenever I'm trying to print out the available ingredients, I get a seg fault.
And when I prompt to enter ingredients, if I say we have 3 available ingredients today, I can only type 2 in (as shown in the output picture)
int get_ingredients(char** ingredients,int* num_ingredients) {
char **ingredients_array = NULL; /*this is an array of pointers points to single ingredient in get_item*/
int temp,i,j;
ingredients = &ingredients_array; /*ingredients is a pointer points to the array of pointers*/
temp = *num_ingredients;
printf("How many available pizza ingredients do we have today? ");
scanf("%d",&temp);
ingredients_array = (char**)calloc(temp, sizeof(char*));
i = 0;
printf("Enter the ingredients one to a line: \n");
while (i < temp){
*(ingredients_array+i) = get_item();
i++;
}
i = 0;
printf("Available ingredients today are: \n");
while(i < temp) {
j = i+1;
printf("%d",j);
print(". ");
printf("%s", **(ingredients_array+i));
i++;
}
*num_ingredients = temp;
return EXIT_SUCCESS;
}
char* get_item(){
int i,a;
char *each_ingredient= (char*)malloc(61*sizeof(char)); /*points to each input*/
a = getchar();
i = 0;
while (a != EOF && (char)a != '\n'){
*(each_ingredient+i)= (char)a;
a = getchar();
i++;
}
*(each_ingredient+i) = '\n';
return each_ingredient;
}
This is the output
There are many issues with your get_ingredients question.
The first issue that I noticed is that you changed the pointer of the parameter ingredients, you changed it to the pointer get_ingredients which was set to NULL. So accessing the data from ingredients pointer from now on will get you a segmentation fault, for trying to access an illegal address.
int get_ingredients(char** ingredients,int* num_ingredients) {
char **ingredients_array = NULL; /*this is an array of pointers points to single ingredient in get_item*/
int temp,i,j;
//ingredients pointer is lost forever and set to the address of the pointer of ingredients_array
ingredients = &ingredients_array; /*ingredients is a pointer points to the array of pointers*/
Now the second issue is more of an optimization thing. You set a variable, and then you changed it on the scanf, making the useless to set it to some value initially.
//Temp is set to num_ingredients, but this is of no use,becuase this value is never used and is overwritten by scanf("%d",&temp);
temp = *num_ingredients;
printf("How many available pizza ingredients do we have today? ");
scanf("%d",&temp);
Should allocate pointer of a pointer to char.
ingredients_array = (char**)calloc(temp, sizeof(char*));
Changes
ingredients_array = (char**)calloc(temp, sizeof(char**));
The while loops can be replaced with a for a loop. Which a more appropriate type of loop for this case.
//This can write it better with a for loop
i = 0;
printf("Enter the ingredients one to a line: \n");
while (i < temp){
*(ingredients_array+i) = get_item();
i++;
}
i = 0;
printf("Available ingredients today are: \n");
//Use for loop intead, because it more appropiate for this case
while(i < temp) {
//better to use i+1 instead of j, simply things
j = i+1;
//These two printf can be on the same line
printf("%d",j);
printf(". ");
//Allocation error?
printf("%s", **(ingredients_array+i));
i++;
}
Using a for loop instead, getting user input from standard function, and using less confusing indexing.
printf("Enter the ingredients one to a line: \n");
//Using for loop
for(int i = 0;i < temp;i++)
{
char ptr[80]; //Store user input
scanf("%s", ptr); //Get user input
ingredients_array[i] = strdup(ptr); //strdup is to make a another string with the same contents
}
printf("Available ingredients today are: \n");
for(int i = 0; i < temp;i++)
{
//These two printf can be on the same line
printf("%d",i+1);
print(". ");
//Allocation error?
printf("%s\n", ingredients_array[i]);
}
*num_ingredients lost its original pointer earlier, so this serves no use.
//This cannot be used because now points to ingredients_array and not to num_ingredients
*num_ingredients = temp;
Now the code with all those changes.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int get_ingredients(char** ingredients,int* num_ingredients) {
char **ingredients_array = NULL; /*this is an array of pointers points to single ingredient in get_item*/
int temp;
printf("How many available pizza ingredients do we have today? ");
scanf("%d",&temp);
ingredients_array = (char**)calloc(temp, sizeof(char**));
printf("Enter the ingredients one to a line: \n");
//Using for loop
for(int i = 0;i < temp;i++)
{
char ptr[80]; //Store user input
scanf("%s", ptr); //Get user input
ingredients_array[i] = strdup(ptr); //strdup is to make a another string with the same contents
}
printf("Available ingredients today are: \n");
for(int i = 0; i < temp;i++)
{
printf("%d. ",i+1);
printf("%s\n", ingredients_array[i]);
}
*num_ingredients = temp;
return EXIT_SUCCESS;
}
int main()
{
char** ingredients;
int a;
int foo = get_ingredients(ingredients, &a);
return 0;
}
Output
How many available pizza ingredients do we have today? 4
Enter the ingredients one to a line:
meat
MEAT
mEaT
no_salas
Available ingredients today are:
1. meat
2. MEAT
3. mEaT
4. no_salad
Related
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.
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));
}
}
So I've got an assignment where my program asks the brand (10 letters), model (10 letters), age (1986 - 2019) and cost (positive real number) of 10 cars and then wants the program to check which car is the oldest and to print out it's brand and model. I don't have a problem with the first part but with the second part.
The code is:
//First part
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define C 10
#define M 11
int main(void)
{
char brand[C][M];
char model[C][M];
int year[C];
float cost[C];
int i, len1, len2, min;
for(i=0; i<C; i++){
printf("Car %d\n", i+1);
do{
printf("Brand: ");
scanf("%s", brand[i]);
len1 = strlen(brand[i]);
} while(len1<0 || len1>10);
do{
printf("Model: ");
scanf("%s", model[i]);
len2 = strlen(model[i]);
} while(len2<0 || len2>10);
do{
printf("Year: ");
scanf("%d", &year[i]);
} while(year[i]<1986 || year[i]>2019);
do{
printf("Cost: ");
scanf("%d", &cost[i]);
} while(cost[i]<=0);
}
//Second part
year[0] = min;
for(i=0; i<10; i++)
if(year[i] < min){
min = year[i];
printf("\nThe oldest car is %s %s\n", brand[i], model[i]);
}
For some reason it either prints out gibberish in the place of brand[i] or if I lose the columns of the if statement prints out all the car brands and their models, where I only want the oldest one.
Aside from scanf not being recommended there are some problems with this code, first when you read the brand and model you do:
do{
printf("Brand: ");
scanf("%s", brand[i]);
len1 = strlen(brand[i]);
} while(len1<0 || len1>10);
The problem here is that you first write the string to brand[i] and then check if it's too long, but you have already written it into the array so if the string is longer than your space you already have a buffer overflow. Limit the size you can read with scanf using scanf("%10s, brand[i]) or better yet use fgets(brand[i], sizeof(brand[i]), stdin).
Next in the second part you use min without initializing it, and you overwrite the content of year[0] with it. You probably wanted something like:
min = 2020; // or a number that will be bigger than all your cars anyway
int older = 0;
i = 0;
for(i=0; i<C; i++){ // Use C here, you have it might as well use it instead of magic numbers
if(year[i] < min){
older = i;
min = year[i];
}
}
printf("\nThe oldest car is %s %s\n", brand[older], model[older]);
but bare in mind that this solution will print multiple cars if they are the oldest ones and have the same year
I have been working on an assignment which is pretty much done, and all I need to do is free the the double pointer allocated memory, but with the loop when I go through the loop it triggers a break point and seems to not clear it all I'm not sure whats triggering it.
Context: the Create Data function is basically a function that returns a malloc.
int main(void){
int i;
static STUDENT** records;
static float averageTotal[SIZE];
createData();
records = calloc(3, sizeof(STUDENT*));
for (i = 0; i < 3; i++){
records[i] = createData();
}
menu(records, userinput, &averageTotal[0]);
int c;
for (c = 0; c < 3; c++){
free(records[c]);
}
free(records);
return 0;
}
STUDENT* createData()
{
STUDENT* result;
result = malloc(3*sizeof(STUDENT*));
return result;
}
EDIT: added Menu for Context
void menu(STUDENT* records, int user_size, float* averageTotal[]){
int menuV = 0;
do{
int userinput;
int i;
static int counter = 0;
printf(" **********************************\n");
printf(" * MENU *\n");
printf(" * 1. Add Student *\n");
printf(" * 2. Display all student records*\n");
printf(" * 3. Quit *\n");
printf(" **********************************\n");
scanf_s("%d%*[^\n]", &userinput); '\n' == getchar();
switch (userinput){
// switch statement with loops.
case 1:do
{
addStudent(records, &counter, user_size);
printf("Add another record? 1(y) 2(n)\n");
scanf_s("%d%*[^\n]", &userinput); '\n' == getchar();
} while (userinput == 1);
break;
case 2:
do{
displayStudent(records, user_size);
printf("Display again? 1(y) 2(n)\n");
scanf_s("%d%*[^\n]", &userinput); '\n' == getchar();
} while (userinput == 1);
break;
case 3:
menuV++;
break;
}
} while (menuV == 0);
}
Edit: added addStudent Function for Context
void addStudent(STUDENT* records[], int* counter, int user_size)
{ // A simple function that lets the user add values to the struct. The counter keeps track and changes the element.
printf("Student: %d", (*counter+1));
printf(" of 3\n");
printf("Enter name:\n");
fgets(records[*counter]->name, 40, stdin);
printf("Enter Exam 1 Score: \n");
scanf_s("%f", &records[*counter]->exam1);
printf("Enter Exam 2 Score: \n");
scanf_s("%f", &records[*counter]->exam2);
printf("Name:%s",records[*counter]->name);
printf("Exam 1:%0.2f\n", records[*counter]->exam1);
printf("Exam 2:%0.2f\n", records[*counter]->exam2);
(*counter)++;
}
There's lots of things wrong here. You seem to have a weak grasp of pointers and dereference.
This line:
static STUDENT** records;
Creates a variable that's a pointer to a pointer to a datatype.
Ideally you should change the declaration to something that's idiomatic and easier to understand without thinking. Something like:
records = calloc(3, sizeof(*records));
In the function CreateData() you're assigning the members of records to a pointer to 3 pointers.
This line:
result = malloc(3 * sizeof(*STUDENT));
Should read:
result = malloc(3 * sizeof(STUDENT));
. The seconds allocates memory for three times the length of the datatype STUDENT. (What you want).
Moving on --
Here is the declaration/definition of the function menu.
void menu(STUDENT* records, int user_size, float* averageTotal[])
And here's how you've used it in your code:
menu(records, userinput, &averageTotal[0]);
the first parameter, records, was defined as a pointer-to-pointer-to-STUDENT. But the definition of menu expects only a pointer-to-STUDENT.
Looking at the rest of the code, it's the definition that's incorrect and not the function call.
Same function:
void menu(STUDENT* records, int user_size, float* averageTotal[])
menu expects a pointer-to-pointer-to-float for its third parameter. But you provided a pointer-to-index in the call here:
menu(records, userinput, &averageTotal[0]);
Without reading much further, it's clear you need to understand pointers better(or stop typing so fast and understand what you're writing!).
Finally, an actual nit-pick. The function CreateData() should be removed and its use should be replaced by function calls to calloc/malloc() directly.
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.