Home > Software engineering >  "pointer" to "array of pointers" how to allocate with malloc and copy with strcp
"pointer" to "array of pointers" how to allocate with malloc and copy with strcp

Time:11-09

The below code is pointer to "array of pointers" code. I am not sure that this is correct.

  tags[0][0] = malloc(sizeof(char)*5);
  strcpy(tags[0][0],"hi");
  tags[0][1] = malloc(sizeof(char)*5);
  strcpy(tags[0][1],"h2");

Can anyone please tell are the above lines correct in following code.

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

int main(void) {
    char *(*tags)[2] = malloc (2 * sizeof *tags);
  
    tags[0][0] = malloc(sizeof(char)*5);
    strcpy(tags[0][0],"hi");
    tags[0][1] = malloc(sizeof(char)*5);
    strcpy(tags[0][1],"h2");
    tags[1][0] = "<head";
    tags[1][1] = "</head>";
  
    for (int i = 0; i < 2; i  ) {
        for (int j = 0; j < 2; j  )
            printf (" %s", tags[i][j]);
    
        putchar ('\n');
    }
  
    free (tags);
}

Is there any difference between the above and array of pointers to pointers?

CodePudding user response:

Yes, the code principle is absolutely correct. It's the correct way to do dynamic allocation of a 2D array.

This

char *(*tags)[2] 

means that tags is a pointer to an array of 2 char pointers.

So when you do

char *(*tags)[2] = malloc (2 * sizeof *tags);

you allocate an array of two arrays of two char pointers. It's equivalent to:

char* tags[2][2];

when not using dynamic allocation.

So yes, the code is fine. That's exactly the way to do it. And you should always do like that when you want a dynamic 2D array.

However, your code lacks:

free(tags[0][0]);
free(tags[0][1]);

BTW: Storing both pointers to dynamic allocated memory and pointers to string literals in the same array is a bit "strange" and can be problematic as you need to track which pointers to free and which not to free.

CodePudding user response:

This looks ok to me. I haven't seen pointers like this very much in practice, but I would describe tags as "A pointer to a 2-size array of character pointers". When you malloc (2 * sizeof *tags);, you create space for two of of these 2-size array of character pointers. This is what you have from each line:

char *(*tags)[2] = malloc (2 * sizeof *tags);

tags -----> [char*][char*]   // index 0 of tags
            [char*][char*]   // index 1 of tags

// You now have 4 character pointers in contiguous memory that don't
// point to anything. tags points to index 0, tags 1 points to index 1.
// Each  1 on *(tags) advances the pointer 16 bytes on my machine (the size
// of two 8-byte pointers).

Next malloc:

tags[0][0] = malloc(sizeof(char)*5);

                -------> 5 bytes
               |
tags ------> [char*][char*]  // index 0
               ^
               index 0 of tags[0], this now points to 5 bytes

After first strcpy

strcpy(tags[0][0],"hi");

                -------> {'h', 'i', '\0', <2 more> }
               |
tags ------> [char*][char*]  // index 0

Next malloc

tags[0][1] = malloc(sizeof(char)*5);

                       -------> 5 bytes
                      |
tags ------> [char*][char*]  // index 0
                      ^
                      index 1 of tags[0], this now points to 5 bytes

Next strcpy

strcpy(tags[0][1],"h2");

                       -------> {'h', '2', '\0', <2 more> }
                      |
tags ------> [char*][char*]  // index 0

And finally, the string literal assignments

tags[1][0] = "<head";
tags[1][1] = "</head>";

tags -----> [char*][char*]   // index 0 of tags
            [char*][char*]   // index 1 of tags
              |       |
              |       |------> points to string literal "</head>"
              |--------------> points to string literal "<head"

If you really want to clean up properly, you should

free(tags[0][1]);
free(tags[0][0]);
// the order of the above doesn't really matter, I just get in the
// habit of cleaning up in the reverse order that I malloced in.
// But if you free(tags) first, you've created a memory leak, as
// there's now no existing pointers to tags[0][0] or [0][1].
free(tags);

Of course, all memory gets reclaimed by the OS as soon as the process exits anyway.

CodePudding user response:

What you want to achieve is array of strings.

char ***tags = malloc(sizeof(char**) * numberofpointers);

for (int i = 0; i < numberofpointers;   i)
{
    tags[i] = malloc(sizeof(char*) * numberofstringsperpointer);
}

for (int i = 0; i < numberofpointers;   i)
{
    for (int j = 0; j < numberofstringsperpointer;   j)
    {
        tags[i][j] = malloc(sizeof(char) * (numberofcharacterperstring   1));
    }
}

strcpy(tags[0][0], string)
  •  Tags:  
  • c
  • Related