Libra
Libra

Reputation: 2595

Bizarre behavior with 2D Char array in C

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

Upvotes: 0

Views: 227

Answers (3)

bscharan
bscharan

Reputation: 157

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)

Upvotes: 1

dvhh
dvhh

Reputation: 4750

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.

Upvotes: 0

Jaime Aguilar
Jaime Aguilar

Reputation: 56

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

Upvotes: 1

Related Questions