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.