This simple C code about string arrays works while it shoudn't and I don't know why

I know there are other ways to solve this like with a calloc but the question here is why does it work while it shouldn’t?

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

void function (char **, char **);

int main () {
  char *list[2], *list1[] = {"word0", "word1", "word2"};

  function(list, list1);
  return 0;
}

void function (char **list, char **list1) {
  for(int i=0; i<2; i++) {
    printf("Insert string\n");
    scanf("%s", (list+i));          //adds 2 strings in list
  }

  for(int i=0; i<2; i++) {
    printf("%s\n", (list+i));       //reads the strings that I just added but if I place * before (list+i) the code crashes
  }

  printf("%s\n", *(list1+1));    //reads the second string of list1 but if I don't place * before (list+1) it reads some weird chars
}

I was trying to better understand pointers and arrays of strings, I expected that it would not work the way it’s written in the comments in the code.
Like why is the "*" needed before (list1+1) and not before (list+i)

>Solution :

  char *list[2], *list1[] = {"word0", "word1", "word2"};

This line creates 2 arrays of pointers; the second one contains some words, but the first one is never allocated, so it contains garbage data. You need to allocate memory for list.

void function (char **list, char **list1) {
  for(int i=0; i<2; i++) {
    printf("Insert string\n");
    scanf("%s", (list+i));          //adds 2 strings in list
  }

When you calculate (list+1), you get back a char **, the same type as list. Since list was never assigned a value, this could be anywhere. However, scanf expects a char*, so it’s not writing into an element of list, but writing into list as if list was a string. You need to allocate memory for each element you write into list.

You can do either:

  for(int i=0; i<2; i++) {
    printf("Insert string\n");
    char *newValue = malloc(...);
    list[i] = newValue;
    scanf("%s", list[i]);
  }

or

  for(int i=0; i<2; i++) {
    printf("Insert string\n");
    char *newValue = malloc(...);
    scanf("%s", newValue);
    list[i] = newValue;
  }

.

  for(int i=0; i<2; i++) {
    printf("%s\n", (list+i));       //reads the strings that I just added but if I place * before (list+i) the code crashes
  }

%s expects a char*; in the previous step you wrote into list as if it were a char* so now when you attempt to read it, it works. If you pass it *(list+i), you’re asking printf to "print the string at location ‘input text’".

  printf("%s\n", *(list1+1));    //reads the second string of list1 but if I don't place * before (list+1) it reads some weird chars
}

This is the correct approach, the previous one happens to work because of two errors "canceling" each other.

Leave a Reply