Question

What I'm trying to do is pretty straight forward in other languages. But I'm struggling with this in a C project and didn't find a right way to do it in my researches.

What I need to do is:

  1. Declare an global empty array of strings
  2. Inside a function I want to populate this global array with X new strings
  3. In another function, I want loop through all new elements of this array printing them out.

The code I have now is listed below.

#include <stdio.h>

const char *menu[] = {};

void populateMenu(){

    // populate this menu with some itens
    *menu = {
        "New item A",
        "New item B",
        NULL
    };
}

int main(int argc, const char * argv[])
{

    // 1. print inicial menu

    int menuAlen = sizeof(menu)/sizeof(*menu);
    int i;
    for(i = 0; i < menuAlen; i++){
        printf("%s\n", menu[i]);
    }

    // 2. populate the menu
    populateMenu();

    // 3. print it again with new values
    int menuBlen = sizeof(menu)/sizeof(*menu);
    for(i = 0; i < menuBlen; i++){
        printf("%s\n", menu[i]);
    }

    return 0;
}

I'm currently getting this error on build time.

main.c:16:16: Expected expression

Line 16 is the first line inside populateMenu function.

Can someone help me out with this? Thanks in advance.

Best. George.

Was it helpful?

Solution

You should declare menu as a pointer to [some array of] pointer strings:

char**menu;

You need to know the number of menu entries. So declare also

size_t nb_menu;

and have some way to compute it at runtime. (I leave that up to you, but you cannot use sizeof which is a compile-time thing).

You then allocate in the heap, using calloc(3), that array:

menu = calloc (nb_menu+1, sizeof(char*));
if (!menu) { perror("calloc menu"); exit (EXIT_FAILURE); };

I'm doing nb_menu+1 because you probably want to NULL terminate your menu.

Now you could fill it, e.g.

menu[0] = "Some string";

or better yet, use strdup(3).

You should have a convention (and document it) about when and which pointers are into the heap -i.e; malloc-ed or calloc-ed and who should free them.

You should later free(3) your pointers to avoid memory leaks. You can only free a pointer obtained by malloc or calloc or strdup (which calls malloc) etc...

On Linux, you should learn how to use valgrind. Perhaps using Boehm Garbage Collector could help you. Certainly, understand what garbage collectors are and learn a lot more about C memory management.

Actually, you could use flexible array members and have your menu be a pointer to

struct menu_st {
  unsigned nb_entries;
  char* entry_array[]; // nb_entries elements in the array
};

Read about the C memory model.

Don't forget to compile with all warnings and debug info (e.g. gcc -Wall -g) and learn how to use the debugger (e.g. gdb). Be very scared of undefined behavior.

OTHER TIPS

#include <stdio.h>

const char **menu = NULL;

void populateMenu(){
    static const char *items[] = {
        "New item A",
        "New item B",
        NULL
    };
    menu = items;
}

int menuLen(const char **menu){
    int len = 0;
    if(!menu) return 0;
    while(*menu++)
        ++len;
    return len;
}

int main(int argc, const char * argv[]){
    // 1. print inicial menu

    int menuAlen = menuLen(menu);
    int i;
    for(i = 0; i < menuAlen; i++){
        printf("%s\n", menu[i]);
    }

    // 2. populate the menu
    populateMenu();

    // 3. print it again with new values
    int menuBlen = menuLen(menu);
    for(i = 0; i < menuBlen; i++){
        printf("%s\n", menu[i]);
    }

    return 0;
}

I hate global variables. I suggest you create the array inside main() and pass it throughout your code as needed.

// #includes ...
// prototypes
int main(void) {
    char menu[1000][80]; // space for 1000 strings each up to 79 characters long
    size_t nmenu;        // number of string in menu

    nmenu = populate(menu); // change contents of array, set nmenu
    menuprint(menu, nmenu); // print

    return 0;
}

The rest of the program (the functions populate() and menuprint()) is up to you.

Note: the 1000 and 80 are large(ish) estimates. A better way to do it would be with dynamic memory allocation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top