C Dynamic Array Size

119 Views Asked by At

Hello I am new to coding and was just wondering why the below code:

#include <stdio.h>

int main() {

for(int i = 0; 1 ; i++) {

    char x;
    char z[1+i];
    x=getchar();
    if (x == '\n'){
        *(z+i) = '\0';
        printf("%s",z);
        break;}
    *(z+i) = x;
    printf("%s, %d = %c, i = %d\n",z, (z+i),*(z+i),i);
}

return 0;
}

of C does not work for inputs that are more than 15 characters? (I don't think it is beacuse of the current state of my pc since I tried it with an online compiler and it still breaks at 16 chars, but then again I am new to coding.) Would appreciate any help. Thank you. (If the answer is something like: "Thats not possible in C" or something like that please don't leave it at that and explain why it is not possible).

PS: I cheked some of the similar questions to mine but I don't get what any of them are doing, if this post is a duplicate, I would really appreciate if you could link me to the post that solves my issue, I will delete this post shortly after if that is the case.

This is the input and output of my program for 16 chars,

1234567890123456
1, 6421952 = 1, i = 0
12, 6421953 = 2, i = 1
123, 6421954 = 3, i = 2
1234, 6421955 = 4, i = 3
12345, 6421956 = 5, i = 4
123456, 6421957 = 6, i = 5
1234567, 6421958 = 7, i = 6
12345678, 6421959 = 8, i = 7
123456789, 6421960 = 9, i = 8
1234567890, 6421961 = 0, i = 9
12345678901, 6421962 = 1, i = 10
123456789012, 6421963 = 2, i = 11
1234567890123, 6421964 = 3, i = 12
12345678901234, 6421965 = 4, i = 13
123456789012345, 6421966 = 5, i = 14
1234567890123456p@, 6421967 = 6, i = 15

Process returned 0 (0x0)   execution time : 4.076 s
Press any key to continue.

And this is the input and output for 15 chars,

123456789012345
1, 6421952 = 1, i = 0
12, 6421953 = 2, i = 1
123, 6421954 = 3, i = 2
1234, 6421955 = 4, i = 3
12345, 6421956 = 5, i = 4
123456, 6421957 = 6, i = 5
1234567, 6421958 = 7, i = 6
12345678, 6421959 = 8, i = 7
123456789, 6421960 = 9, i = 8
1234567890, 6421961 = 0, i = 9
12345678901, 6421962 = 1, i = 10
123456789012, 6421963 = 2, i = 11
1234567890123, 6421964 = 3, i = 12
12345678901234, 6421965 = 4, i = 13
123456789012345, 6421966 = 5, i = 14
123456789012345
Process returned 0 (0x0)   execution time : 4.150 s
Press any key to continue.

As you can see it works fine for 15 chars of input, but breaks at 16, this is the problem that I want to be solved.

4

There are 4 best solutions below

1
soda2718 On BEST ANSWER

I know that I didn't explain the purpose of the code but here is the final version of the code which is highly based on FuzzFoo's answer.

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

int str_input(char **y);

int main()
{
    char * y = NULL;

    str_input(&y);

    printf("%s\n", y);

    str_input(&y);

    printf("%s", y);

    free(y);

    return (0);
}

int str_input(char **y)
{
    int i;
    char x;

    for (i = 0; 1 ; i++)
    {
        x = getchar();
        *y = (char *)realloc(*y, (2 + i) * sizeof(char));

        if (*y == NULL)

            break;

        if (x == '\n')
        {
            (*y)[i] = '\0';
            break;
        }

        (*y)[i] = x;
        (*y)[i + 1] = '\0';
    }

    return (0);
}

Hopefully this version of the code isn't trying to utilize any undefined behaviour and works for (virtually) all lengths of input. Purpose of it is to make the str_input function sort of assign strings to a pointer variable.(I know it is a little more complicated than that, but it is what it is.)(And also memory is assigned dynamically so it actually works for longer inputs.)

3
FuzzFoo On

Taking the above into consideration try this instead.

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

int main()
{
    int i;  
    char x;
    char *z = NULL;

    for (i = 0; 1; i++)
    {
        x = getchar();
        z = (char *) realloc(z, (2 + i) * sizeof(char));
        if (z == NULL)
            break;
        z[i+1] = '\0';
        if (x == '\n')
        {
            z[i] = '\0';
            printf("%s", z);
            break;
        }
        z[i] = x;
        printf("%s, %p = %c, i = %d\n", z, (z+i), z[i] , i);
    }

    free(z);

    return (0);
}
2
chrslg On

You are lucky that it went so well

  1. You are printing strings without ensuring that there is a terminal 0 somewhere. Except when you see a \n, but for all other cases, nothing says there is a terminal 0

  2. Each z is a different array (with a different size). You cannot count on it to inherit to whatever you already put in its predecessor. Sure, you cannot swear it won't neither. And for a while, it works: the address of z is apparently the same for some of the iterations (probably because of some alignment considerations, but you are not supposed to count on that any way. Compiler works in mysterious ways. You are not supposed to make any assumptions about where each z will be located.

So, if you want to print z at each iteration, you must ensure that, at each iterations, it contains all the chars, followed by a terminal 0.

What you did, is printing a each ith iteration, a string z, whose ith char contain what getch gave. And all other chars of z (the i-1 first ones, but also whatever is after i, including what should be a terminal 0) are indeterminate. And happens to be, for a while, what was left from previous iteration for the i-1 first one, and some initial 0 for whatever is after (because, well, nothing says that this memory is initialized to 0, but, more often than not, it happens to be initial values of things)

1
Vlad from Moscow On

As this call of printf

printf("%s, %d = %c, i = %d\n",z, (z+i),*(z+i),i);

occurs in each iteration of the for loop even when the new line character '\n' was not yet detected then the array does not contain a string except the last iteration of the for loop that is broken by the break statement. And the conversion specification %s expects a pointer to a string.

Also to output a pointer you have to use the conversion specifier p.

You could change the call of printf the following way

printf("%.*s, %p = %c, i = %d\n", i + 1, z, ( void * )(z+i),*(z+i),i);

This call outputs exactly i + 1 characters stored in the array in a current iteration.

Though in any case the program has undefined behavior because it is unspecified whether the variable length array defined in each itertion of the for loop preserves data stored in it in a previous iteration.