0

I am new to C and still trying to figure out pointer.

So here is a task I am stuck in: I would like to assign 10 fruit names to a pointer of array and print them out one by one. Below is my code;

#include <stdio.h>
#include <string.h>

int main(){
    char *arr_of_ptrs[10];
    char buffer[20];
    int i;
    for (i=0;i<10;i++){
        printf("Please type in a fruit name:");
        fgets(buffer,20,stdin);
        arr_of_ptrs[i]= *buffer;
    }
    int j;
    for (j=0;j<10;j++){
        printf("%s",*(arr_of_ptrs+j));
    }

}

However after execution this, it only shows me the last result for all 10 responses. I tried to consult similar questions others asked but no luck.

My understanding is that 1) pointer of array has been allocated memory with [10] so malloc() is not needed.

2) buffer stores the pointer to each individual answer therefore I dereference it and assign it to the arr_of_ptrs[i] I am unsure if arr_of_ptrs[i] gets me a pointer or a value. I thought it is definitely a pointer but I deference it with * the code and assign it to *buffer, program would get stuck.

If someone could point out my problem that would be great.

Thanks in advance

  • 1
    And `arr_of_ptrs[i]= *buffer;` should be puking a phat warning. That's assigning `char` to `char*`, which is wrong regardless of the posted problem. – WhozCraig Jun 02 '20 at 22:50
  • 2
    Try: `arr_of_ptrs[i]= strdup(buffer);`. That is, make a copy of the string to be referenced by each array entry. Don't forget to `free` each of the array pointers when no longer needed. – kaylum Jun 02 '20 at 22:51

2 Answers2

0

The misunderstanding is probably that "Dereferencing" an array of characters, unlike dereferencing a pointer to a primitive data type, does not create a copy of that array. Arrays cannot be copied using assignment operator =; There a separate functions for copying arrays (especially for 0-terminated arrays of char aka c-strings, and for allocating memory needed for the copy):

Compare a pointer to a primitive data type like int:

int x = 10;
int *ptr_x = &x;
int copy_of_x = *ptr_x;  // dereferences a pointer to x, yielding the integer value 10

However:

char x[20] =  "some text";  // array of characters, not a single character!
char *ptr_x = &x[0];  // pointer to the first element of x
char copy_of_first_char_of_x = *ptr_x;  // copies the 's', not the entire string

Use:

char x[20] = "some text";
char *ptr_x = &x[0];
char *copy_of_x = malloc(strlen(ptr_x)+1);  // allocate memory large enough to store the copy    
strcpy(copy_of_x,ptr_x);  // copy the string.
printf("%s",copy_of_x);

Output:

some text
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
  • hello in fact the solution I read does not use strdup() but strcpy() instead. Is there a potential issue with it? Thanks! – JAMES جواد Jun 04 '20 at 04:42
  • yes, with `strcpy` you must make sure that you have allocated enough memory for the target, i.e. you need a preceding `malloc` (see edited answer). `strdup` does both - allocate and copy - as one command. – Stephan Lechner Jun 04 '20 at 15:37
0

Three erros, 1. You must allocate memory for elements of elements of arr_of_ptrs, now you only allocate the memory for elements of arr_of_ptrs on stack memory. 2. arr_of_ptrs[i]= *buffer; means all of the arr_of_ptrs elements are pointed to same memory address, which is the "buffer" pointer. So all the elements of arr_of_ptrs will be same to the last stdin input string. 3. subsequent fgets() call has potential problem, one of the explaination could be here

A quick fix could be,

#include <stdio.h>
#include <string.h>

int main(){

    const int ARR_SIZE = 10, BUFFER_SIZE = 20;
    char arr_of_ptrs[ARR_SIZE][BUFFER_SIZE];
    char *pos;
    int i, c;

    for (i = 0; i < ARR_SIZE; ++i) {
        printf ("Please type in a fruit name: ");
        if (fgets (arr_of_ptrs[i], BUFFER_SIZE, stdin) == NULL) return -1;
        if ((pos = strchr(arr_of_ptrs[i], '\n')))
            *pos = 0;
        else
            while ((c = getchar()) != '\n' && c != EOF) {}
    }
    for (i = 0; i < ARR_SIZE; ++i)
        printf("%s\n", arr_of_ptrs[i]);

    return 0;
}
Dawn16
  • 140
  • 8
  • If you don't want to deal with the 3rd problem, and have sufficient memory in your environment, just let BUFFER_SIZE large enough to hold all string in domain. – Dawn16 Jun 03 '20 at 02:11
  • It works but i was wondering, how variable c gets put into each element in arr_of_ptrs[i] after it collects each character from stdin? Also the solution suggests using strcpy() after the memory allocation. Any potential problem with it? Cheers – JAMES جواد Jun 04 '20 at 04:21
  • @James 1. Variable c deals with buffer overflow problem. Suppose code is fgets(str, 5, stdin) which reads 5 bytes, then input "abcdef", str will "abcd" with a '\0' at the end, in total 5 bytes. At this time, call next fgets(str, 5, stdin), str starts with "ef" because "ef" is the remained characters from last call. Variable c is used to "eat" the remaining characters in stdin if user input longer than fgets() specified. Variable c has no relationship with arr_of_ptrs. You could run your old program, try input a string longer than 20 characters and see the problem. – Dawn16 Jun 05 '20 at 06:57
  • @James 2. Always you can type "man strcpy" on your linux terminal, see Linux manual page's "BUGS" section, it lists all its potential problem include whether it is thread-safe, etc. Linux manual page is one of the official sources to understand API. As a learner, I suggest you do a malloc() and strcpy() solution by yourself, since in real work, most of time large array needs go to heap instead of stack. In embedded software, stack's frame size could be pretty small. – Dawn16 Jun 05 '20 at 06:58