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)