最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

gcc - How can argv in C be an array if its size is determined dynamically? - Stack Overflow

programmeradmin12浏览0评论

I don’t understand how it works under the hood. How can C determine how much memory to allocate for argv when the program doesn’t know the number of arguments until it is running?

I tried understanding how C can figure out how much memory to allocate for argv[], since the program doesn’t know how many arguments will be passed until it's actually running. I asked GPT but i didn't really like its answer

I don’t understand how it works under the hood. How can C determine how much memory to allocate for argv when the program doesn’t know the number of arguments until it is running?

I tried understanding how C can figure out how much memory to allocate for argv[], since the program doesn’t know how many arguments will be passed until it's actually running. I asked GPT but i didn't really like its answer

Share Improve this question asked Mar 31 at 23:25 Ignacio Dias GundinIgnacio Dias Gundin 173 bronze badges New contributor Ignacio Dias Gundin is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 5
  • If you mean the char *argv[] passed to main(), the memory is allocated before the C program runs, and it is also passed argc the number of arguments. So C does not need to figure out how much memory was needed. – Weather Vane Commented Mar 31 at 23:42
  • 2 Why do you call it an array? Because the parameter declaration is often done with int main(int argc, char *argv[]){...? But that [] has not the same meaning in a parameter declaration than in a variable declaration. I am not a c-spec lawyer, but in my book, if it were an array, then sizeof(argv) would depend on the number of arguments. But it is just the size of a pointer. So, imho, it is just a pointer, as far as the called main is concerned (maybe it was a pointer in the code of whoever filled that memory, but that wasn't even in the C code) – chrslg Commented Mar 31 at 23:48
  • Try int main(int argc, char *argv[]){ char *argv2[]={"one", "two", "three", NULL}; printf("%ld %ld\n", sizeof(argv), sizeof(argv2));}, and call your program with 3 arguments. On my machine it prints 8 and 24 (size of a pointer, and size of an array of 4 pointers). So argv is a pointer. argv2 is an array in this example. – chrslg Commented Mar 31 at 23:50
  • @Weather Vane, Also, argv is NULL-terminated. So there's not one but two ways of determining the number of elements in argv. – ikegami Commented Apr 1 at 0:05
  • argv is kind of similar to environment variables. It is OS-specific - the OS will have support for it in some way and the CRT might have to call APIs to obtain it, then re-package it in the format expected by main(). – Lundin Commented Apr 1 at 6:39
Add a comment  | 

3 Answers 3

Reset to default 4

How can argv in C be an array if its size is determined dynamically?

Parameter char *argv[] is not an array even though it has a []. argv is a pointer to the first element of an array of pointers. The first array elements point to strings. The last one is equal to NULL.


How can C determine how much memory to allocate for argv when the program doesn’t know the number of arguments until it is running?

The memory is allocated before the program is called. The calling code (e.g. the operating system's command line processor) has determined the memory allocation. How it does that is not specified by C.


I asked GPT but i didn't really like its answer

Not really surprising.

C does not do that... There is no memory allocation at program loading. No size to figure out...

When the program is loaded the operating system allocates memory for the arguments and passes a null-terminated series of pointers to them to the program. And another block of pointers pointing to the environment variables.

The program gets argc a simple counter with the number of pointers, them the address of the pointer to the 1st argument. A NULL is passed to signal the end of the arguments, so it is not even needed to know the argument count, as noted by @ikegami.

The C runtime library is responsible for setting the value of argc and argv appropriately before calling the function main. This means that an array will have to be created whose char * members point to individual strings. The number of strings and the length of these strings are both variable.

Depending on the operating system used, the runtime library may have to allocate the memory for storing the strings, in addition to allocating the memory for the array of pointers to these strings.

In many cases, the runtime library is itself programmed in C, and it will likely have access to the function malloc or similar function.

The function malloc can be used for creating an array of variable length of elements of type char *. This function can also be used for allocating the memory necessary for storing the strings, where each string also has a variable length.

In my example program below, I am using the function malloc for creating an array of variable length similar to argv, where each element of the array is a char * to a string, which is also of variable length. After this array has been created, its content is printed.

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

int main( void )
{
    int desired_size;
    char **arr;
    int c;

    // read number of strings from user
    printf( "Number of strings: " );    
    if ( scanf( "%d", &desired_size ) != 1 || desired_size < 0 )
    {
        printf( "Error reading input!" );
        exit( EXIT_FAILURE );
    }

    // discard the remainder of the line
    while ( ( c = getchar() ) != '\n' && c != EOF )
        ;

    // allocate memory for array with room for an additional
    // NULL pointer to mark the end
    arr = malloc( ( desired_size + 1 ) * sizeof arr[0] );
    if ( arr == NULL )
    {
        printf( "Memory allocation error!\n" );
        exit( EXIT_FAILURE );
    }

    // fill array with pointers to strings
    for ( int i = 0; i < desired_size; i++ )
    {
        char input[200];

        // prompt user for input
        printf( "Please enter string #%d: ", i + 1 );

        // read input from user
        if ( fgets( input, sizeof input, stdin ) == NULL )
        {
            printf( "Input error!\n" );
            exit( EXIT_FAILURE );
        }

        // remove newline character from input, if it exists
        input[strcspn(input,"\n")] = '\0';

        // allocate memory for new string
        arr[i] = malloc( strlen(input) + 1 );
        if ( arr[i] == NULL )
        {
            printf( "Memory allocation error!\n" );
            exit( EXIT_FAILURE );
        }

        // copy the input string to the newly allocated memory
        strcpy( arr[i], input );
    }

    // write a NULL pointer to the end of the array, because
    // argv also has a NULL pointer at the end
    arr[desired_size] = NULL;

    // print the content of the array
    printf( "\nThe array has the following content:\n" );
    for ( char **p = arr; *p != NULL; p++ )
    {
        printf( "%s\n", *p );
    }

    // free the strings
    for ( char **p = arr; *p != NULL; p++ )
    {
        free( *p );
    }

    // free the main array
    free( arr );
}

This program has the following behavior:

Number of strings: 5
Please enter string #1: apple
Please enter string #2: banana
Please enter string #3: cherry
Please enter string #4: dragonfruit
Please enter string #5: elderberry

The array has the following content:
apple
banana
cherry
dragonfruit
elderberry

Side note: In the program above, I am using the function scanf to read an integer from the user. I am doing this for simplicity. However, it is worth noting that using scanf is generally not advisable for line-based user input. See this answer of mine to another question on why this is not advisable, and which better alternatives are available.

发布评论

评论列表(0)

  1. 暂无评论