0

I'm getting some weird behavior I dont understand with this code:

char strings[5][4];

for (int i = 0; i < 5; ++i) {
    scanf("%s", strings[i]);
}
for (int i = 0; i < 5; ++i) {
    printf("%s\n", strings[i]);
}

If I enter 5 strings like:

this
is
a
test
help

I end up with something like this in the second for loop:

thisis
is
a
testhelp
help

Any idea what's happening? driving me crazy

Libra
  • 2,544
  • 1
  • 8
  • 24
  • 3
    Sorry, I failed to mention: the structure of the array is this: char strings[5][4]; – Libra Oct 04 '19 at 02:59
  • 2
    Strings is too short to properly write a null character. – Robert Prévost Oct 04 '19 at 03:03
  • I dont understand what youre saying? If I fill out each string entirely they behave even more strange, for instance if I gave it ["test", "fake", "core", "bird", "town"] it would give me ["testfakecorebirdtown", "fakecorebirdtown", "corebirdtown" "corebird", "town"] – Libra Oct 04 '19 at 03:06
  • More info: if I increase the string buffer to 5, so that it exceeds the size of the string being input by 1, it functions normally. Anyone have any idea what is happening? I am absolutely bewildered. – Libra Oct 04 '19 at 03:09
  • 2
    Needs to be strings[5][5] as you need to save the null character as well. C terminates a string when it encounters a null character. – fractals Oct 04 '19 at 03:17
  • 1
    scanf allow to limit the maximum number of character in the string `%4s` would fit into a `char[5]` – dvhh Oct 04 '19 at 03:40
  • You said the array is `char strings[5][4];`. That information needs to be in the question. Please read this: [mre] – Keith Thompson Oct 04 '19 at 03:50
  • Does this answer your question? [How to access items in a 3 dimensional array of strings?](https://stackoverflow.com/questions/69921207/how-to-access-items-in-a-3-dimensional-array-of-strings) – einpoklum Nov 10 '21 at 23:13
  • @einpoklum this is a 3 year old question that has an answer – Libra Nov 10 '21 at 23:14
  • @Laif: Yes, but the two questions are about the same issue, and this question doesn't say how the `strings` array was defined, so I decided to mark it as a dupe. The comment is generated automatically. – einpoklum Nov 10 '21 at 23:15

3 Answers3

1

So the way that an array of char works is that it allocates each character in the designated array; however, the last character is a null character which delimitates the "string":

char str[4] = {'n','o','t','\0'};
char str[4] = {'t','h','i','s'};

So if you add one more than the size it works due that it actually saves the space and your scanf works fine. So the solution, would be to either make the buffer one size bigger if it's a set size, or read in the string, and add the null character by hand

1

the Problem actually lies with the character array, you defined.

char strings[5][4]

the program allocates "strings" 20 "char" sized memory blocks.

lets suppose starting address is 0x00 so memory block from 0x00 to 0x20 (Mentioned in decimal system for easy understanding) is allocated to "strings"

this means strings[0] points to 0x00

this means strings[1] points to 0x04

this means strings[2] points to 0x08

this means strings[3] points to 0x12

this means strings[4] points to 0x16

now in the "scanf" is basically reading each character until endline and storing it in corresponding memory blocks

for (int i = 0; i < 5; ++i) {
    scanf("%s", strings[i]);
}

so from your question, "this" is stored in 4 blocks of strings[0] and there is no space for endline character "is" occupies 3 characters from strings[1] with third being endline character.

Now coming to printf function for arrays.it considers array as pointer and iterates until it finds endline statement.

for (int i = 0; i < 5; ++i) {
    printf("%s\n", strings[i]);
}

For strings[0] , printf function takes pointer 0x00 and iteartes until it finds endline character(ie at 0x06)

so "thisis" is printed and for string[1] , pointer is at 0x04 and so "is" is printed.

now if you give your input string of sizw more than 4 you can observe that the string is overflowed to next string

for (int i = 0; i < 1; ++i) {
                scanf("%s", strings[i]);
            }
    
for (int i = 0; i < 2; ++i) {
                printf("%s\n", strings[i]);
            }


**INPUT:**
        thisab

    

in the above code, only strings[0] is assigned with value "thisab" but it printf produces

**OUTPUT:**
                thisab
                ab

to avoid such problem , use Strings or define size of each row equal to (max_input_size+1)

einpoklum
  • 118,144
  • 57
  • 340
  • 684
bscharan
  • 137
  • 1
  • 13
0

Your strings are wrongly sized for the inputs.

string in C are zero-terminated, meaning that they will contain the desired content plus an ending zero character (so that most function would understand where your string end).

Your array will be allocated contiguously onto the stack, meaning that before your first loop your memory would look like this:

000011112222333344445555

content will be arbitrary, but for ease of understanding your array would look like this

  1. [[0,0,0,0],[1,1,1,1],[2,2,2,2],[3,3,3,3],[4,4,4,4],[5,5,5,5]]
  2. [['t','h','i','s'],['\0',1,1,1],[2,2,2,2],[3,3,3,3],[4,4,4,4],[5,5,5,5]]
  3. [['t','h','i','s'],['i','s','\0',1][2,2,2,2],[3,3,3,3],[4,4,4,4],[5,5,5,5]]

in a contiguous view

't','h','i','s','i','s','\0',12222333344445555

resulting in the observed behavior

You can fix the issue in 2 ways

  • limit the string output by using %4s in the output format.
  • limit the input to 3 chars %3s so that input would not overlap when writing the terminating zero char.
  • grow the size of your string to accommodate the terminating zero character.
dvhh
  • 4,724
  • 27
  • 33