-2

Is it possible to redeclare a variable in C? Or at least do it with pointers I want to redeclare the size of a variable in an array, what I want to try is not to ask the user the size of the array variable. I did an example which i don't even know if it's good Anyone know the answer?

int i;

int main() {
    int aUniverso[i];
    int ii = 0;
    
    printf("Put your numbers, if u wanna leave put a number - to '0' \n");
    
    do{
        printf("Posicion[%d]: ", i);
        scanf("%d", &aUniverso[i]);
        i++;
    }
    while (aUniverso[i] >= 0);

    printf("U = {");
    for (ii = 0; ii < i; ii++) {
       printf("%d, ", aUniverso[ii]);
    }   
}

Know if I can redeclare the size of a variable in a loop automatically while the user is placing values.

Chris
  • 26,361
  • 5
  • 21
  • 42
  • 3
    no, it's not possible – user253751 Dec 09 '22 at 21:08
  • I *think* you might be asking essentially the same question as [this one](https://stackoverflow.com/questions/74743925). If so, see the comments there. – Steve Summit Dec 09 '22 at 21:10
  • Even if you could (which you can't) your loop logic is broken regardless. You're checking `aUniverseo[i]` *after* the increment of `i`, which *was* indexing the just-read value prior to the increment. You'd effectively be checking indeterminate data; not what the user just stored. – WhozCraig Dec 09 '22 at 21:11
  • 1
    If you have an array of size, say, 10, you can easily store and use 5 elements in it. There's no rule that says you always have to fill an array to its defined size. You can't make an array *bigger*, but you can accomplish about the same thing by using `malloc` and `realloc`. – Steve Summit Dec 09 '22 at 21:12
  • 1
    That behavior is what linked-lists do exhibit. – Jishan Shaikh Dec 09 '22 at 21:12
  • 3
    Please note that in the code shown, because `i` is a global variable, it is initialized to `0`, but that means you've declared `aUniverso` to be an array of size `0`. – Chris Dec 09 '22 at 21:12
  • It is not possible to directly change the size of an array once it has been declared. However, it is possible to use a pointer to dynamically allocate memory for an array using the malloc function from the standard library. – sinanorl Dec 09 '22 at 21:13

3 Answers3

1

If you are trying to have an array that can grow at runtime, you can use dynamic memory allocation with malloc and realloc. The following features no error-checking, which is left as an exercise for the reader.

To avoid having to reallocate too often, when necessary, we double the size of the array. In the below I have started with a count of 1, but that would just as easily be a larger number like 64, in which case a reallocation might never occur for trivial test input.

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

int main(void) {
    size_t count = 1;
    int *numbers = malloc(sizeof(int) * count);
    size_t i;

    for (i = 0; i < count; i++) {
        scanf("%d", &numbers[i]);

        if (numbers[i] < 0) break;

        if (i == count - 1) {
            count *= 2;
            numbers = realloc(numbers, sizeof(int) * count);
        }
    } 

    for (size_t c = 0; c < i; c++) {
        printf("%d\n", numbers[c]);
    }
    
    free(numbers);

    return 0;
}
Chris
  • 26,361
  • 5
  • 21
  • 42
  • 2
    Shouldn't `i == count - 1` be `i == count`? – shahar Dec 09 '22 at 21:36
  • No. Look at the loop condition. If `i == count` the for loop has already ended. – Chris Dec 09 '22 at 21:38
  • 1
    What bothers me is that in you always call `realloc` when you still have enough space for one more number. The condition should be `i == count` and the loop condition should be `i <= count`. Yes, it is a bit confusing, but it is more efficient. – shahar Dec 09 '22 at 21:44
  • You could move that code to _after_ the check for a break. But since the memory grows exponentially, allocations are logarithmic to the size of the input, which mitigates this. – Chris Dec 09 '22 at 21:53
  • I have edited so the array only "grows" on the last for loop iteration if user input has not caused the loop to break. – Chris Dec 09 '22 at 21:56
1

In C, it is not possible to simply resize an array. However, there are several other options for solving the problem:

Solution #1: Define an upper-bound of how many numbers you will need, and make the array that size.

Example:

#include <stdio.h>

#define MAX_NUMBERS 100

int main( void )
{
    int numbers[MAX_NUMBERS];
    int i;

    for ( i = 0; i < MAX_NUMBERS; i++ )
    {
        printf( "Please enter #%d, or -1 to stop: ", i + 1 );

        if ( scanf( "%d", &numbers[i] ) != 1 || numbers[i] == -1 )
            break;
    }

    printf( "\nYou entered the following numbers:\n" );

    for ( int j = 0; j < i; j++ )
    {
        printf( "#%d: %d\n", j + 1, numbers[j] );
    }
}

This program has the following behavior:

Please enter #1, or -1 to stop: 7
Please enter #2, or -1 to stop: 3
Please enter #3, or -1 to stop: 5
Please enter #4, or -1 to stop: 8
Please enter #5, or -1 to stop: 3
Please enter #6, or -1 to stop: -1

You entered the following numbers:
#1: 7
#2: 3
#3: 5
#4: 8
#5: 3

However, the disadvantages of this solution are that

  • you have a hard limit on how many numbers you can have, and
  • setting this limit very high may cause you to waste a lot of memory.

If you don't want these disadvantages, then an alterantive would be:

Solution #2: Use a dynamically allocated array and resize it as necessary.

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

int main( void )
{
    int *numbers = NULL;
    int i;

    for ( i = 0; ; i++ ) //infinite loop
    {
        //attempt to create/resize buffer to desired capacity
        //NOTE: calling realloc with a NULL argument is equivalent
        //      to calling malloc
        numbers = realloc( numbers, (i+1) * sizeof(int) );
        if ( numbers == NULL )
        {
            fprintf( stderr, "Memory allocation error!\n" );
            exit( EXIT_FAILURE );
        }

        printf( "Please enter #%d, or -1 to stop: ", i + 1 );

        if ( scanf( "%d", &numbers[i] ) != 1 || numbers[i] == -1 )
            break;
    }

    printf( "\nYou entered the following numbers:\n" );

    for ( int j = 0; j < i; j++ )
    {
        printf( "#%d: %d\n", j + 1, numbers[j] );
    }

    //cleanup
    free( numbers );
}

This solution has the same behavior:

Please enter #1, or -1 to stop: 7
Please enter #2, or -1 to stop: 3
Please enter #3, or -1 to stop: 5
Please enter #4, or -1 to stop: 8
Please enter #5, or -1 to stop: 3
Please enter #6, or -1 to stop: -1

You entered the following numbers:
#1: 7
#2: 3
#3: 5
#4: 8
#5: 3

This solution has the advantage that you are only limited by available memory. However, a disadvantage of this solution is that realloc may have to copy the entire array to a new memory location, every time you call that function. If you only have a few numbers, then this should not be a problem. However, if you have thousands or even millions of numbers, then it probably will be a problem.

One way of solving this problem would be to not only increase the size of the array by a single element in every loop iteration, but to instead double the size of the array whenever more capacity is needed. That way it is guaranteed that, on average, every number will not have to be copied more than twice by realloc.

Here is an example:

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

int main( void )
{
    int capacity = 100;
    int *numbers;
    int i;

    //allocate initial array
    numbers = malloc( capacity * sizeof(int) );
    if ( numbers == NULL )
    {
        fprintf( stderr, "Memory allocation error!\n" );
        exit( EXIT_FAILURE );
    }

    for ( i = 0; ; i++ ) //infinite loop
    {
        //double the capacity of the array, if necessary
        if ( i == capacity )
        {
            capacity *= 2;

            numbers = realloc( numbers, capacity * sizeof(int) );
            if ( numbers == NULL )
            {
                fprintf( stderr, "Memory allocation error!\n" );
                exit( EXIT_FAILURE );
            }
        }

        printf( "Please enter #%d, or -1 to stop: ", i + 1 );

        if ( scanf( "%d", &numbers[i] ) != 1 || numbers[i] == -1 )
            break;
    }

    printf( "\nYou entered the following numbers:\n" );

    for ( int j = 0; j < i; j++ )
    {
        printf( "#%d: %d\n", j + 1, numbers[j] );
    }

    //cleanup
    free( numbers );
}
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
0

In the spirit of the OP, another offering:

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

int main( void ) {
    int *vals = NULL; // starting out with nothing
    size_t nVals = 0;

    puts( "Enter as many counting numbers as you like. 0 to end input" );

    do {
        // note that sizeof doesn't presume an int
        // less maintenance when changing this to 'doubles'
        vals = realloc( vals, (nVals+1) * sizeof *vals );
        if( vals == NULL ) {
            printf( "Realloc failed\n" );
            return 1; // can't go on...
        }

        while( scanf( "%d", vals + nVals ) != 1 ) {
            scanf( "%*[^\n]" ); // discard whatever is waiting.
            printf( "Bad input\n" );
        }
    } while( vals[ nVals++ ] > 0 );

    puts( "\nHere are your numbers:" );
    for( size_t i = 0; i < nVals - 1; i++ )
        printf( "%d\n", vals[ i ] );
    
    free( vals );

    return 0;
}

Practically speaking, incrementally growing the stored value array from zero, in this instance, is a minor consideration, imho... Here we see that passing a NULL pointer to realloc() initially causes it to function as if it were malloc().

Enter as many counting numbers as you like. 0 to end input
9 8 7 6 5 4 3 2 1 0

Here are your numbers:
9
8
7
6
5
4
3
2
1
Fe2O3
  • 6,077
  • 2
  • 4
  • 20