0

The following is a snippet of code that parses tokens and stores them. The code compiles and works.

Code

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

int storeTokens(char *src, char *delim, char **storage, size_t len) {
    int idx = 0;
    char str[100] = {0};
    char *token = NULL;
    char *saveptr = NULL;

    // copy string so we don't modify the source
    if (snprintf(str, sizeof(str), "%s", src) < 0) {
        return 0;
    }

    // Loop through string and parse out tokens
    token = strtok_r(str, delim, &saveptr);
    while ((token != NULL) && (idx < len)) {
        snprintf(storage[idx], sizeof(storage[idx]), "%s", token);
        strcpy(storage[idx++], token);
        token = strtok_r(NULL, delim, &saveptr);
    }

    // Print the tokens
    int i = 0;
    for (i = 0; i < idx; i++) {
        printf("fun: %s\n", storage[i]);
    }

    return idx; // number of tokens found
}

int main() {
    int i = 0;

    char teststr[] = "This*is*my*string*.";
    char *storageptr[72];
    char storage[72][255];

    // Assign storage space to the pointers
    for (i = 0; i < 72; i++) {
        storageptr[i] = storage[i];
    }

    // Parse the tokens
    int numtokens = storeTokens(teststr, "*", storageptr, 72);

    // Print the tokens
    for (i = 0; i < numtokens; i++) {
        printf("storage: %s\n", storage[i]);
    }

    return EXIT_SUCCESS;
}

Output

fun: This
fun: is
fun: my
fun: string
fun: .
storage: This
storage: is
storage: my
storage: string
storage: .

The function stores the string with the char **storage variable. The reason for this being a double pointer is so the function can be used on any storage regardless of the length.

My problem is passing the storage into the function. As you can see in main, I created storageptr to point to storage before passing it to the function.

This seems convoluted and unnecessary. Not to mention the time wasted looping and linking each string. However I can't figure out how to pass storage directly into the function without creating storageptr.

I've done reading such as Passing an array of strings to a C function by reference, but nothing really clicks. I can't seem to figure out how to properly pass storage into the function.

6
  • I blogged about char ** here: dima.to/blog/?p=478 Its just a list of strings, and its already a pointer so you pass it as is. But, I think what might be causing you problems is finding a distinction between a 2D array and pointers. Commented Feb 22, 2018 at 13:04
  • In your storeTokens function, storage is a pointer to a pointer. storage[idx] is a pointer. And doing sizeof on a pointer (like e.g. sizeof(storage[idx])) returns the size of the pointer and not what it points to. That is seems to work indicates that you're on a 64-bit system where pointers are 64 bits (8 bytes). Try using longer sub-strings than 8 characters and see it fail. Commented Feb 22, 2018 at 13:06
  • As for your problem, have you thought about dynamic allocation? Perhaps you should do some research about malloc, realloc and free? Commented Feb 22, 2018 at 13:07
  • @Someprogrammerdude due to the nature of where the code is being used, dynamic allocation isn't an option. As for the sizeof, I figured that was wrong. Thanks for pointing that out. I'll change it to strcpy since it's not the target of the topic. Commented Feb 22, 2018 at 13:13
  • @Alexandru the issue is I have char storage[72][255] and I'm looking to pass that to a function with char **storage. The issue I'm having is I can't understand how to pass the 2D array directly into the function without creating pointers to each element. Commented Feb 22, 2018 at 13:17

2 Answers 2

1

Using a C99 or C11, having optional VLA support, compatible compiler you can pass directly the 2D array specifying dynamically the size of your array:

int storeTokens(char *src, char *delim, size_t len, size_t size, char storage[len][size]);

Call from main:

int numtokens = storeTokens(teststr, "*", 72, 255, storage);

If you have a C11 compiler to be sure that it supports VLA's (that are optional for C11) check the symbol STDC_NO_VLA, if it is defined the compiler does not support VLA's.

Sign up to request clarification or add additional context in comments.

2 Comments

Wow, that works! I had no idea you could use the variables declared in the function within the function declaration itself. This is allows me to use any size array which was the intention of the double pointer. Is there anything further I should about that or is that basically the gist of it?
This is called VLA variable length array. I.e. see en.cppreference.com/w/c/language/array. I forget to specify that in a C11 compiler the support for C11 is optional.
1

Unless you need to keep the argument as a pointer to pointer (to char), then to be able to pass the array of arrays (of char) directly you need to change the function signature:

int storeTokens(char *src, char *delim, char (*storage)[255], size_t len)
//                                           ^^^^^^^^^^^^^^^

Now you can pass storage from the main function:

storeTokens(teststr, "*", storage, 72)

The problem is that while arrays can decay to a pointer to its first element, it's not "recursive".

If you have an array like yours

char storage[72][255];

then when it decays to a pointer to its first element it is &storage[0], which is a pointer to an array. This secondary array will not decay, so passing storage will pass a pointer to an array (of type char (*)[255]).

If you must pass a char **, then the intermediate storageptr array is needed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.