-1

So I'm trying to make a char**, I fully understand how it works in the background and all that stuff but I don't seem to understand how to write the code for it. I want to make a pointer to an array of chars which has a name in it. I need help with storing a string in it (using strcpy() ) and print it after that.

char** name = (char**)malloc((strlen("MyName") + 1) * sizeof(char*));
strcpy(name, "MyName"); // I get an error right here
  • 6
    Just use one `*`. With two `*`, you are declaring an array of pointers, which could be used for an array of strings. BTW, if you're actually writing C code, [don't cast the results of malloc](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). C++ is a different language, and a different rules apply. – user3386109 Apr 12 '19 at 21:15
  • 1
    @user3386109; With two `*`s he is not declaring an array of pointers but declaring a pointer to pointer to `char` data type. – haccks Apr 12 '19 at 21:17
  • When you get an error, the first step is to read the error message. – eerorika Apr 12 '19 at 21:17
  • @haccks That's a distinction without a difference, since a pointer to a single `char` is indistinguishable from a pointer to an array of `char`. – user3386109 Apr 12 '19 at 21:19
  • @user3386109; Pointer to a `char`, pointer to an array of `char` and an array of pointers to `char` are all different data types. None of the three are compatible with each other. – haccks Apr 12 '19 at 21:21
  • @haacks You're just splitting hairs over the meaning of the word "array", which really isn't useful to anyone. – user3386109 Apr 12 '19 at 21:24
  • What language C or C++ as they are completely different. – 0___________ Apr 12 '19 at 21:52
  • by the way, `char **name;` declares a "pointer to pointer to `char`", not "pointer to array of `char`". An actual "pointer to array of `char`" would be declared something like `char (*name)[42];` – newacct Apr 14 '19 at 23:38
  • @newacct in a general case, yes it does and you are right, but in this case the pointer points to another pointer, yes, but that itself is an array. so it's just easier to say that it's pointer to an array of chars – AggressiveMail Apr 16 '19 at 05:07

3 Answers3

0

If you really want a pointer to an char array, you could do the following:

char** name = (char**)malloc(sizeof(char*)); //initialize the pointer
*name = (char*)malloc((strlen("MyName") + 1) * sizeof(char)); //initialize the array
strcpy(*name, "MyName");
RomCoo
  • 1,868
  • 2
  • 23
  • 36
0

First thing you should understand is that declaring a variable as a single pointer or a double pointer (or any other n pointer) doesn't actually tell whether the underlying variable holds a single value or an array of values.

Single pointer points to a memory address on which actual value is stored. Double pointer points to a memory address on which single pointer is stored, and so on.

Now, to make a pointer to an array of char pointers you can use a single char pointer (char*) but I recommend to use double char pointer (char**) for maintainability purposes.

Consider the following code:

char** names = (char**)malloc(100 * sizeof(char*));

It will allocate memory space for 100 char pointers (char*) on heap and return you a double pointer (char**) to the first single pointer (char*) in that memory space. This means you will be able to save 100 char pointers (or 100 names in your case) inside that memory space. Then you can use them like this:

char* name0 = "First Name"; // Saved on stack
char* name1 = malloc((strlen("Second Name") + 1) * sizeof(char));  // Saved on heap
strcpy(name1, "Second Name");

names[0] = name0;
names[1] = name1;

Also, please note that when saving a string on heap you need to add one more place for null character (manually).

Emir
  • 380
  • 3
  • 11
0

So I'm trying to make a char**, I fully understand how it works in the background and all that stuff but I don't seem to understand how to write the code for it.

Umm... No, not quite.

To declare a pointer-to-char, you simply decalre:

    char *name = malloc (strlen("MyName") + 1);

Why? When you make your call to malloc, malloc allocates a block of memory providing strlen("MyName") + 1 bytes and returns the starting address to that block of memory -- which you assign to name. You then can copy "MyName" to name (with 1-byte remaining for the nul-terminating character). The approach would be:

    size_t len = strlen ("MyName");
    char *name = malloc (len + 1);      /* allocate len + 1 bytes */
    if (name == NULL) {                 /* validate EVERY allocation */
        perror ("malloc-name");
        /* handle error by returning or exiting */
    }
    memcpy (name, "MyName", len + 1);   /* no need to scan again for \0 */

    /* do something with name - here */

    free (name);    /* don't forget to free name when you are done */

What then does char** do?

When you are dealing with a pointer-to-pointer-to-char, you must first allocate for some number of pointers, then you can allocate and assign a block of memory to each of the pointers and use each pointer just as you have used name above.

For example:

    /* array of ponters to string-literals for your source of strings */
    char *band[] = { "George", "Ringo", "Paul", "John" };
    char **names;
    size_t nmembers = sizeof band / sizeof *band;

    /* allocate nmembers pointers */
    names = malloc (nmembers * sizeof *names);
    if (names == NULL) {                /* validate EVERY allocation */
        perror ("malloc-name_pointers");
        /* handle error by returning or exiting */
    }

    /* now loop allocating for each name and copy */
    for (size_t i = 0; i < nmembers; i++) {
        size_t len = strlen (band[i]);      /* get length */
        names[i] = malloc (len + 1);        /* allocate */
        if (names[i] == NULL) {             /* validate EVERY allocation */
            perror ("malloc-names[i]");
            /* handle error by returning or exiting */
        }
        memcpy (names[i], band[i], len + 1);/* no need to scan again for \0 */
    }

    /* output each */
    for (size_t i = 0; i < nmembers; i++)
        printf ("member[%zu]: %s\n", i + 1, names[i]);

Freeing names is a two step process. You must free the memory allocated to each of the names pointers and then free the pointers themselves, e.g.

    for (size_t i = 0; i < nmembers; i++)
        free (names[i]);    /* free each allocated names[i] */
    free (names);           /* free pointers */

Now hopefully you more closely "... fully understand how it works". Let me know if you have any questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85