Passing Pointers to Pointers into Functions in C - arrays

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

Related

seg fault in c with pointers

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

What am I getting wrong on malloc and realloc understanding?

I was trying to make an array that would resize whilst the program is running. I have come to knowledge of malloc and realloc functions but it seems I'm getting something wrong apparently. Here's the function that I wrote that creates an array based on how many cycles is the loop making.
int* flexibleArray() {
int *arrayFlex = NULL;
int number=0, cnt=0;
while (number!=-1) {
printf("\nInsert the variable: ");
scanf("%d", &number);
if (number==-1){
break;
}
cnt+=1;
arrayFlex = realloc(arrayFlex, cnt * sizeof(int));
arrayFlex[cnt-1] = number;
}
return arrayFlex;
}
I tried to read the documentation I found on the internet about it, I can't then retrieve the new array after the reallocation.
int *array;
array = flexibleArray();
int arraySize = (sizeof(array))/(sizeof(int));
for(int i=0; i<arraySize; i++) {
printf("%d ", array[i]);
}
basically this is where I'm testing the function to see if it does what it should.
I'm new to C, sorry guys.
Thanks
Something like this should do it.
int* flexibleArray() {
int *arrayFlex = NULL; // needs to be a pointer
int number=0, cnt=0;
while (number!=-1) {
printf("\nInsert the variable: ");
scanf("%d", &number);
if (number==-1){
break;
}
cnt+=1;
arrayFlex = realloc(arrayFlex, cnt * sizeof(int));
arrayFlex[cnt-1] = number;
}
return arrayFlex;
}
EDIT: fixed typos.

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

Issue with array of pointers

I'm writing a program to alphabetize inputted names and ages. The ages are inputted separately, so I know I need to use an array of pointers to tie the ages to the array of names but I can't quite figure out how to go about doing it. Any ideas?
So far, my program only alphabetizes the names.
/* program to alphabetize a list of inputted names and ages */
#include <stdio.h>
#define MAXPEOPLE 50
#define STRSIZE
int alpha_first(char *list[], int min_sub, int max_sub);
void sort_str(char *list[], int n);
int main(void)
{
char people[MAXPEOPLE][STRSIZE];
char *alpha[MAXPEOPLE];
int num_people, i;
char one_char;
printf("Enter number of people (0...%d)\n> ", MAXPEOPLE);
scanf("%d", &num_people);
do
scanf("%c", &one_char);
while (one_char != '\n');
printf("Enter name %d (lastname, firstname): ", );
printf("Enter age %d: ", );
for (i = 0; i < num_people; ++i)
gets(people[i]);
for (i = 0; i < num_people; ++i)
alpha[i] = people[i];
sort_str(alpha, num_people);
printf("\n\n%-30s5c%-30s\n\n", "Original List", ' ', "Alphabetized List");
for (i = 0; i < num_people; ++i)
printf("-30s%5c%-30s\n", people[i], ' ', alpha[i]);
return(0);
}
int alpha_first(char *list[], int min_sub, int max_sub)
{
int first, i;
first = min_sub;
for (i = min_sub + 1; i <= max_sub; ++i)
if (strcmp(list[i], list[first]) < 0)
first = i;
return (first);
}
void sort_str(char *list[], int n)
{
int fill, index_of_min;
char *temp;
for (fill = 0; fill < n - 1; ++fill){
index_of_min = alpha_first(list, fill, n - 1);
if(index_of_min != fill){
temp = list[index_of_min];
list[index_of_min] = list[fill];
list[fill] = temp;
}
}
}
Most of your printfs are syntax errors, as in
printf("Enter name %d (lastname, firstname): ", );
printf("Enter age %d: ", );
or bomb right away, since you pass an int (' ') as a pointer:
printf("\n\n%-30s5c%-30s\n\n", "Original List", ' ', "Alphabetized List");
As a first step, get all your %s right and show us what you really compiled, not some random garbage. And crank your compiler's warning level to the maximum, you need it! What is
#define STRSIZE
supposed to mean when STRSIZE is used as an arary dimension? You have a serious cut&paste problem, it would appear.
Creating a struct would probably be easier: i.e
struct person {
char name[STRSIZE];
int age;
}
Otherwise, if you must do it the way you're trying, just create an extra array of the indexes. When you move a name, you also move the index on the array... when you're done sorting names, just sort the ages to match the indexes.

Resources