• is it possible to point to a slice of an array without malloc or VLAs?

    From Mark Summerfield@21:1/5 to All on Wed Aug 28 07:06:43 2024
    I'm using getopt_long() to process a command line.
    So after a typical call I might have:

    argv == {"./efind", "-D", "-x", "one", "two", "three", "four"}
    optind == 3

    What I'd like to do (without copying or mallocing and without using a VLA)
    is to get a pointer to a slice of argv, specifically,
    {"one", "two", "three", "four"}.
    In Python terms argv[optind:argc].

    Is this possible in C?

    At the moment I store argv, optind, and argc and handle the slice using a loop:

    if (config->optind < config->argc)
    for (int i = config->optind; i < config.argc; ++i)
    process(config->argv[i]);

    This works fine, so really I'm just wondering if there's a nicer way.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Phil Ashby@21:1/5 to Mark Summerfield on Wed Aug 28 09:13:39 2024
    On 28/08/2024 08:06, Mark Summerfield wrote:
    I'm using getopt_long() to process a command line. So after a typical
    call I might have:

    argv == {"./efind", "-D", "-x", "one", "two", "three", "four"} optind
    == 3

    What I'd like to do (without copying or mallocing and without using a
    VLA) is to get a pointer to a slice of argv, specifically, {"one",
    "two", "three", "four"}. In Python terms argv[optind:argc].

    Is this possible in C?

    To answer the specific question, I would use pointer arithmetic,
    provided there is no intention to modify values, ie:

    char **slice = argv + config->optind;

    thus slice now points at the appropriate part of argv and can be indexed
    or dereferenced / incremented to access elements.

    At the moment I store argv, optind, and argc and handle the slice
    using a loop:

    if (config->optind < config->argc) for (int i = config->optind; i < config.argc; ++i) process(config->argv[i]);

    This works fine, so really I'm just wondering if there's a nicer
    way.
    I don't think so, other than to drop the outer check as the loop
    condition provides the same boundary.

    Phil.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Mark Summerfield on Wed Aug 28 09:50:54 2024
    Mark Summerfield <mark@qtrac.eu> wrote or quoted:
    argv == {"./efind", "-D", "-x", "one", "two", "three", "four"}
    . . .
    In Python terms argv[optind:argc].

    #include <stdio.h>

    int main()
    { char const * const argv[] =
    { "./efind", "-D", "-x", "one", "two", "three", "four" };

    size_t const argc = sizeof( argv )/ sizeof( 0[ argv ]);
    printf( "%zu\n", argc );

    char const * const * rest = argv + 3; /* <<< answer to the question */

    for( char const * const * entry = rest; entry < argv + argc; entry++ )
    printf( "%.32s\n", *entry ); }

    If that's not your jam, you can pretty much 86 all the "const"
    declarations in the program above. But if you're rolling
    in from Python, where "const" is ghost, it's hella tight
    to be able to use "const" again. You'd be missing out on the
    gnarliest feature in C!

    In Python, slices are always copied. Here in the C program
    above, the "slice" shares memory with the base array.
    (There's no such thing as "slices" in C.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Blue-Maned_Hawk@21:1/5 to Mark Summerfield on Wed Aug 28 14:25:59 2024
    Mark Summerfield wrote:

    I'm using getopt_long() to process a command line.
    So after a typical call I might have:

    argv == {"./efind", "-D", "-x", "one", "two", "three", "four"}
    optind == 3

    What I'd like to do (without copying or mallocing and without using a
    VLA)
    is to get a pointer to a slice of argv, specifically,
    {"one", "two", "three", "four"}.
    In Python terms argv[optind:argc].

    Is this possible in C?

    Yes.

    const char * argv_slice[argc - optind] = &argv[optind];





    --
    Blue-Maned_Hawk│shortens to Hawk│/blu.mɛin.dʰak/│he/him/his/himself/Mr. blue-maned_hawk.srht.site
    This subroutine must not be called from any thread.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to bluemanedhawk@invalid.invalid on Wed Aug 28 08:33:32 2024
    Blue-Maned_Hawk <bluemanedhawk@invalid.invalid> writes:

    Mark Summerfield wrote:

    I'm using getopt_long() to process a command line.
    So after a typical call I might have:

    argv == {"./efind", "-D", "-x", "one", "two", "three", "four"}
    optind == 3

    What I'd like to do (without copying or mallocing and without
    using a VLA)
    is to get a pointer to a slice of argv, specifically,
    {"one", "two", "three", "four"}.
    In Python terms argv[optind:argc].

    Is this possible in C?

    Yes.

    const char * argv_slice[argc - optind] = &argv[optind];

    Presumably the declaration that was intended is something more
    like

    const char *(*argv_slice)[argc - optind] = (void*) &argv[optind];

    It should be noted that this solution satisfies the stated
    requirement of not using a VLA, but it does rely on using
    a variably modified type.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ben Bacarisse@21:1/5 to bluemanedhawk@invalid.invalid on Wed Aug 28 16:29:58 2024
    Blue-Maned_Hawk <bluemanedhawk@invalid.invalid> writes:

    Mark Summerfield wrote:

    I'm using getopt_long() to process a command line.
    So after a typical call I might have:

    argv == {"./efind", "-D", "-x", "one", "two", "three", "four"}
    optind == 3

    What I'd like to do (without copying or mallocing and without using a
    VLA)
    is to get a pointer to a slice of argv, specifically,
    {"one", "two", "three", "four"}.
    In Python terms argv[optind:argc].

    Is this possible in C?

    Yes.

    const char * argv_slice[argc - optind] = &argv[optind];

    First, the OP did not want to use a VLA and, second, that initialisation
    is invalid. Third, if a VLA is used, the pointers would be copied and
    the OP did not want that either.

    --
    Ben.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mark Summerfield@21:1/5 to Phil Ashby on Thu Aug 29 07:52:02 2024
    On Wed, 28 Aug 2024 09:13:39 +0100, Phil Ashby wrote:
    [snip]
    To answer the specific question, I would use pointer arithmetic,
    provided there is no intention to modify values, ie:

    char **slice = argv + config->optind;

    thus slice now points at the appropriate part of argv and can be indexed
    or dereferenced / incremented to access elements.
    [snip]

    Thank you, that works great. I now do that plus store the slice's size using: argc - optind

    I tried to get the size using

    #define ARRAYSIZE(a) (&(a)[1] - (a))

    char **folders = argv + optind;
    int num_folders = argc - optind;
    int size = ARRAYSIZE(folders);
    printf("%d %d\n", num_folders, size);

    but size was always 1.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ben Bacarisse@21:1/5 to Mark Summerfield on Thu Aug 29 11:04:01 2024
    Mark Summerfield <mark@qtrac.eu> writes:

    On Wed, 28 Aug 2024 09:13:39 +0100, Phil Ashby wrote:
    [snip]
    To answer the specific question, I would use pointer arithmetic,
    provided there is no intention to modify values, ie:

    char **slice = argv + config->optind;

    thus slice now points at the appropriate part of argv and can be indexed
    or dereferenced / incremented to access elements.
    [snip]

    Thank you, that works great. I now do that plus store the slice's size using: argc - optind

    I tried to get the size using

    #define ARRAYSIZE(a) (&(a)[1] - (a))

    The difference between a pointer to the second element of an array and a pointer to the first will always be 1.

    Another way to look at this is to expand the expression.

    a[1] means *(a+1)
    &a[1] means &*(a+1)
    &*(a+1) is the same as a+1 (barring some details; see 6.5.3.2 p3)
    &a[1] - a means a+1 - a or just 1

    char **folders = argv + optind;
    int num_folders = argc - optind;
    int size = ARRAYSIZE(folders);
    printf("%d %d\n", num_folders, size);

    but size was always 1.

    Another fact that might help you is that the argv array will have a null pointer as it's last element so you may not need to remember the length
    of the slice since it is the tail slice of a null-terminated array.

    --
    Ben.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)