This creates a pointer to the beginning of the array of two pointers.
void **p;
p = malloc(2 * sizeof(void *));
for (int i = 0; i < 2; ++i) {
p[i] = (void *)malloc(sizeof(void *));
}
This creates a pointer to the beginning of the array of two pointers.
void *c = *p;
And this should change the value of the first pointer in the array, right?
I want the first item in array points to my int.
int *a = (int *)malloc(sizeof(int));
*a = 5;
// c points to *p, the first item in array
// *c should be value of the first item in array then
*c = a;
But this doesn't work.
c should be same as *p(p[0]), so when I change c value, it should change *p(p[0]) value as well.
What am I missing?
I believe the point you are missing is that when you loop allocating p[i] = malloc (sizeof (void*)) you are replacing the addresses at both p[0] and p[1] -- which were already valid pointers to begin with.
Specifically, p = malloc(2 * sizeof(void *)); allocates a block of memory for 2-pointers and assigns the beginning address of that block to p. At this point, both p[0] and p[1] are valid (but Uninitialized) pointers. When you create c, it holds the same Uninitialized address of the first pointer in the allocated block assigned to p. At this point neither c or p[0] point anywhere and neither points at the other -- they just hold the same indeterminate address as their value.
When you assign c = a, now c holds a valid address, but p[0] remains Uninitialized. You must initialize p[0] in the same way before you can use the address it holds. There is no need to allocate further. For example:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
void **p = malloc (2 * sizeof *p), /* allocate storage for 2 pointers */
*c = *p; /* c holds the UNINITIALIZED/indeterminate address of the 1st pointer */
int *a = malloc (sizeof *a);
if (!p || !a) {
perror ("malloc-p_or_a");
return 1;
}
*a = 5; /* assign 5 to allocated int */
c = a; /* initialize address held by pointer c to a, p[0] still uninitialized */
*p = c; /* initialize address help by pointer p[0] to c */
printf ("\n a - value at %p : %d\n c - value at %p : %d\np[0] - value at %p : %d\n",
(void*)a, *a, c, *(int*)c, p[0], *(int*)p[0]);
...
As mentioned in the comment, if you are only storing single addresses at p[0] and p[1], then any further allocation is superfluous. You already have valid storage for a pointer you can reference at both p[0] and p[1]. That doesn't mean you can't allocated further, p itself still holds the beginning address for the original block allocated -- so it can still be freed (no memory leak), but you don't provide any additional storage by replacing the pointers at p[0] and p[1] with individually allocated pointers.
Now when you do allocate, you assign a new address as the values for both p[0] and p[1], e.g.
for (int i = 0; i < 2; i++) /* now loop initializeing p[i] */
if (!(p[i] = malloc (sizeof (void*)))) { /* assigns NEW address to p[i] */
perror ("malloc-p[i]");
return 0;
}
...
(In C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?)
Again, at this point, you must initialize the address stored in the block of memory with it's beginning address at p[0] and p[1], e.g.
int b = 10; /* new integer value */
p[0] = &b; /* assign address to pointer at p[0] */
c = p[0]; /* assign to pointer at c */
printf ("\n a - value at %p : %d\n c - value at %p : %d\np[0] - value at %p : %d\n",
(void*)a, *a, c, *(int*)c, p[0], *(int*)p[0]);
}
Example Use/Output
Above is a complete program that makes use of p[0] and p[1], both before and after your for loop allocations. If you compile and run it, you would receive:
$ ./bin/voidptr_int
a - value at 0x12a6280 : 5
c - value at 0x12a6280 : 5
p[0] - value at 0x12a6280 : 5
a - value at 0x12a6280 : 5
c - value at 0x7ffc47fdec6c : 10
p[0] - value at 0x7ffc47fdec6c : 10
It's an interesting exercise, but I believe where you were confused is after you declare void *c = *p; neither c or *p (which is the same as p[0]) point to each other -- they simply hold the same uninitialized/indeterminate address. The compounding things you allocation in the for loop changed the addresses held by both p[0] and p[1] so that whatever address was there before is overwritten with the address of the newly allocated pointers. I'm not sure which of the those two were causing the most confusion, but I suspect it was either one or the other.
c will get a copy of *p. After that, there is no connection between the two. Changing one will not change the other.
If you want to change p[0] thru c, c must be a pointer-to-pointer-to-void, void **c = p;. Then you can assign *c = a; to change p[0] (and leak the memory you allocated for p[0]).
I want the first item in array points to my int.
There are two cases (read x as 0 < x < N, where N is number of void * allocated to p) :
CASE I: p[x] pointers pointing to valid memory locations and use another pointer to make changes to the value of those memory locations.
CASE II: p[x] pointers not pointing to valid memory locations and use another pointer to make p[x] pointers pointing to some valid memory location.
Looks like you are confused between these two cases because you are allocating memory to p[x] pointers and then trying to assign some other memory location to *p (p[0]) using some other pointer c. With this, you end up leaking memory in your program because of not properly handling the allocated memory.
First I would like to point out couple of things in your code:
Here, you are allocating memory of void * size:
p[i] = (void *)malloc(sizeof(void *));
^^^^^^^^
If you want void pointers p[x] to point to memory location which hold an int
value, you should do:
p[i] = (void *)malloc(sizeof (int));
The type of c is void *, so *c type is void. Compiler must be throwing warning/error on this statement because void is an incomplete type and its not assignable:
*c = a;
From C11 Standard#6.2.5p19:
19 The void type comprises an empty set of values; it is an incomplete object type that cannot be completed.
Now, lets discuss the CASE I and II in detail:
CASE I: p[x] pointers pointing to valid memory locations and use another pointer to make changes to the value of those memory locations.
void **p;
p = malloc(2 * sizeof(void *));
if (NULL == p) {
fprintf (stderr, "Failed to allocate memory");
exit(EXIT_FAILURE);
}
for (int i = 0; i < 2; ++i) {
p[i] = malloc(sizeof (int));
if (NULL == p[i]) {
fprintf (stderr, "Failed to allocate memory");
exit(EXIT_FAILURE);
}
}
Now, the void pointers p[x] pointing to memory locations of type int.
Assume, you want to assign value (or make changes) to p[0] memory location using some other pointer:
void *c = *p; // or void *c = p[0];
int a = 5;
*(int *)c = a; // need to type cast c to the type of memory it will point to
printf ("%d\n", *(int *)*p); // or printf ("%d\n", *(int *)p[0]);
Once done with pointers, make sure free the allocated memory. Here, you need to free p[x] pointers and then pointer p.
CASE II: p[x] pointers not pointing to valid memory locations and use another pointer to make p[x] pointers pointing to some valid memory locations.
In this case, you don't need to allocate memory to p[x] pointers.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
void **p;
p = malloc(2 * sizeof(void *));
if (NULL == p) {
fprintf (stderr, "Failed to allocate memory");
exit(EXIT_FAILURE);
}
void **c = p;
int *a = malloc(sizeof(int));
if (NULL == a) {
fprintf (stderr, "Failed to allocate memory");
exit(EXIT_FAILURE);
}
*a = 5;
*c = a;
printf ("p: %p\n", (void *)p);
printf ("c: %p\n", (void *)c);
printf ("a: %p\n", (void *)a);
printf ("*c: %p\n", (void *)*c);
printf ("*p: %p\n", (void *)*p);
printf ("%d\n", *(int *)*p);
free(a);
free(p);
return 0;
}
Output:
p: 0x7fe603c05710
c: 0x7fe603c05710
a: 0x7fe603c05720
*c: 0x7fe603c05720
*p: 0x7fe603c05720 // *p pointer is pointing to memory location allocated to pointer a
5
Note: Whether to type cast malloc result or not is opinion based. So, whatever you choose is up to you but make sure to be consistent everywhere in the code that you write.
Related
I am trying to allocate individual elements of two dimensional array in function call.
I am getting the pointer reference char ***a pointer in function parameter like this int substr(char *arr,char c,char ***a,int k)
But I am getting segFault at realloc line. I am not getting any help from -Wall -Wextra. In this example the function substr allocate for 1 index element of two passed two dimensional array
But I like to allocate memory in called function
#include <stdio.h>
#include <malloc.h>
#include <string.h>
int substr(char *arr, char c, char ***a, int k)
{
*(a + k) = realloc(a, 5);
return 0;
}
int main()
{
char *arr = "this is a new string. check it out";
char **a;
a[0] = malloc(5);
//....some code
//...
int count = substr(arr, ' ', &a, 1);
return 0;
}
From the conversation in the comments, there's some confusion about a[0]. Let's simplify it by working with char *.
// Declare the variable a which stores a pointer to a char.
char *a;
// Same as *a = 'b'
a[0] = 'b';
a[0] tries to access the memory a points to, same as *a. But a was never initialized, it points at some random memory you don't have access to, or is out of bounds. Segfault.
a has to have memory allocated to it to store 'b'.
// `a` points at 5 bytes of memory
// This is the same as `char *a; a = malloc(5)`.
char *a = malloc(5);
// The first byte of malloc'd memory is set to 'b'.
a[0] = 'b';
Now let's do it with an array of strings.
char **a;
a[0] = "some string";
Same problem. a is uninitialized and points at some random memory. a[0] = "some string"; tries to dereference a and segfaults.
So we need to first allocate space to store the pointers to the strings.
// Allocate space for 5 pointers.
// This is the same as `char **a; `a = malloc(...);`
char **a = malloc(sizeof(char *) * 5);
// Dereference the first pointer and have it point to a string.
a[0] = "some string";
Now to your code. Same thing.
char **a = malloc(sizeof(char *) * 5);
// Derefrence the first pointer in a and have it point to 5 bytes of memory.
a[0] = malloc(5);
If you want to reallocate the memory in a[0] you reallocate a[0], not a.
// Reallocate the 5 bytes of a[0] and return a pointer to 10 bytes.
// Assign the new pointer to a[0].
a[0] = realloc(a[0], 10);
If you want to do this in a function, pass in a pointer to the memory work with that. The function doesn't know nor care about the array a. Just the string.
// Note there's no need to pass in an array index.
void substr(char **dest) {
// dest is pointer to the pointer in a[0].
// *dest is the pointer in a[0], the malloc(5).
// Grow its memory and reassign it back to a[0].
*dest = realloc(*dest, 10);
// Assign to a[0] to demonstrate it works.
strcpy(*dest, "012345678");
}
int main(void) {
char **a = malloc(sizeof(char *) * 5);
a[0] = malloc(5);
substr(&a[0]);
puts(a[0]);
}
We can simplify this.
First, since a is allocated in main it can use automatic memory. This is memory which is automatically deallocated when the function exits. Because main is the first function it will be the last to exit, so any automatic memory in main will last for the whole program.
We can't use automatic memory in substr because it will be deallocated when substr returns.
Second, there's no need to allocate memory to a[0] if you're going to immediately realloc it. If you give realloc a null pointer it will allocate new memory.
int main(void) {
char *a[5];
a[0] = NULL;
substr(&a[0]);
puts(a[0]);
}
Finally, we can initialize all the pointers of a to NULL using a little syntactic trick.
int main(void) {
// Same as char *a[5] = {NULL, NULL, NULL, NULL, NULL};
char *a[5] = {NULL};
substr(&a[0]);
puts(a[0]);
}
Suppose i write,
char **p;
p[0] = strdup("hello");
Strdup creates a duplicate string in heap with ending character '\0'; As p is pointer to pointer of char, p[0] = strdup("hello") seems perfectly fine for me. But why am i getting segmentation fault.
Let's look at a simpler example. Suppose you say
int *ip;
ip[0] = 5;
ip is a pointer to one or more ints -- but it's not initialized, so it points nowhere, so ip[0] isn't a valid memory location, so we can't store the value 5 there.
In the same way, when you said
char **p;
p is a pointer that points nowhere. If it did point somewhere, it would point to another pointer. But it doesn't point anywhere, so
p[0] = strdup("hello");
blows up.
To fix this, you need to make p point somewhere, and specifically to memory allocated to hold one or more pointers. There are many ways to do this:
char *q;
p = &q; /* way 1 */
char *a[10];
p = a; /* way 2 */
p = malloc(10 * sizeof(char *)); /* way 3 */
or instead of using a pointer, use an array to start with:
char *p[10]; /* way 4 */
After any of those, p[0] = strdup("hello") should work.
For way 3, we would also need to check that malloc succeeded (that it dd not return a null pointer).
For ways 2 through 4, we could also set p[1] through p[9]. But for way 1, only p[0] is valid.
See also this answer to a different question for more discussion about trying to use uninitialized pointers.
There is declared an uninitialized pointer that has an indeterminate value.
char **p;
so dereferencing the pointer in this expression p[0] (that is equivalent to the expression *p) used in this statement
p[0] = strdup("hello");
invokes undefined behavior because there is an attempt to write to memory using an incorrect pointer value of the expression p[0].
You could write either for example
char *s;
char **p = &s;
p[0] = strdup("hello");
Or
char **p = malloc( sizeof( char * ) );
p[0] = strdup("hello");
That is the pointer to pointer p must point to a valid object. Thus dereferencing the pointer you will get a valid object of the type char * that will be assigned by the value returned by the call of strdup..
First of all, I'm sorry for my bad English.
I have a question about 'realloc' function in language C.
I thought it allocates memories with given length.
When the memories ain't enough for the given length, it copies whole memories to another memory pointer and returns it.
I wanted to use realloc function with preserving the old memories.
So I sentenced another pointer and made it pointing at the old memories.
But whenever 'realloc' function works, it frees the old memories.
How can I preserve old memories?
In addition, I want to know why this is happenend.
the below is code and its result I've used for testing realloc function.
#include <stdio.h>
#include <stdlib.h>
int* ptr1, lenPtr1;
int* ptr2;
void double_ptr1(){
lenPtr1 *= 2;
ptr1 = (int*)realloc(ptr1, sizeof(int) * lenPtr1);
}
void print(){
printf("ptr1 -> %p, *ptr1 = %d\n", ptr1, *ptr1);
printf("ptr2 -> %p, *ptr2 = %d\n", ptr2, *ptr2);
printf("\n");
}
int main(){
lenPtr1 = 10;
ptr1 = (int*)malloc(sizeof(int) * lenPtr1);
ptr2 = ptr1;
*ptr1 = 10;
print();
double_ptr1();
print();
system("pause");
return 0;
}
ptr1 -> 0108D2F0, *ptr1 = 10
ptr2 -> 0108D2F0, *ptr2 = 10
ptr1 -> 00FF5740, *ptr1 = 10
ptr2 -> 0108D2F0, *ptr2 = -17891602
An example incorporating all improvements suggested in the comments and avoiding the use of global variables, and freeing all allocated memory before the program exits. There is only a need to hold the terminal window open on windows, so conditionally enclose the system("pause");.
Putting it altogether, you would have:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int *double_ptr (int *ptr, int *ptrsz) /* pass needed information as parameters */
{
int *newptr = malloc (2 * *ptrsz * sizeof *newptr); /* allocate new block of mem */
if (newptr) { /* validate allocation */
memcpy (newptr, ptr, *ptrsz * sizeof *ptr); /* copy to new block of mem */
*ptrsz *= 2; /* update allocated size */
}
return newptr; /* return pointer */
}
void print (int *ptr1, int *ptr2) /* pass needed information as parameters */
{
/* only one call to printf required */
printf ("ptr1 -> %p, *ptr1 = %d\nptr2 -> %p, *ptr2 = %d\n\n",
(void*)ptr1, *ptr1, (void*)ptr2, *ptr2);
}
int main (void) {
int *ptr1 = NULL, *ptr2 = NULL, lenPtr1 = 10; /* avoid global variables */
if (!(ptr1 = malloc (lenPtr1 * sizeof *ptr1))) { /* validate EVERY allocation */
perror ("malloc-ptr");
return 1;
}
ptr2 = ptr1; /* pointer 1 and 2 hold same address where 10 is stored in memory */
*ptr1 = 10;
printf ("lenPtr1: %d\n", lenPtr1); /* output len, addresses, values */
print (ptr1, ptr2);
if (!(ptr1 = double_ptr (ptr1, &lenPtr1))) { /* double size of ptr1 */
perror ("malloc-double-ptr1");
return 1;
}
printf ("lenPtr1: %d\n", lenPtr1); /* output len, addresses, values */
print (ptr1, ptr2);
free (ptr1); /* free allcoated memory */
free (ptr2);
#if defined (_WIN32) || defined (_WIN64)
system("pause");
#endif
}
Example Use/Output
$ ./bin/doubleptrsz
lenPtr1: 10
ptr1 -> 0xb18260, *ptr1 = 10
ptr2 -> 0xb18260, *ptr2 = 10
lenPtr1: 20
ptr1 -> 0xb186a0, *ptr1 = 10
ptr2 -> 0xb18260, *ptr2 = 10
Let me know if you have further questions.
When you realloc the original pointer, which is pointed by ptr2, the address of the original pointer is removed.
So after you realloc the ptr1, ptr2 points address that does not exists anymore.
If you want to preserve old memory, then you just need to malloc(or calloc) new memory to ptr1 with no realloc original one.
When the memories ain't enough for the given length, it copies whole memories to another memory pointer and returns it.
Not quite. realloc always deallocates the old memory. It may return the same pointer.
From C11 7.20.3.4 realloc...
The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size.... The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object)
I wanted to use realloc function with preserving the old memories.
You can't.
If you need more memory, malloc a new hunk of memory instead of reallocing the old one.
If you want to shrink memory, continue to use the memory as is. It'll work fine, it's just a waste of memory.
I'd recommend neither. Instead, redesign whatever you're doing so the pointer is accessed indirectly. Perhaps using a pointer to a pointer. Or put the pointer inside a struct and pass around a pointer to the struct.
Alternatively, redesign it so you do not need to realloc. For example, when reading from a file use a fixed size buffer to read the line and then copy that to memory with exactly enough space.
// A large buffer to reuse for each line.
char buf[BUFSIZ];
while( fgets(buf, sizeof(buf), fp) ) {
// Allocate exactly enough space for the line.
// In reality, use strdup.
char *string = malloc(strlen(buf) + 1);
strcpy(string, buf);
}
Or change to a data structure which does not rely on a single block of memory. For example, a linked list instead of an array.
In addition, I want to know why this is happened.
There are many implementations of malloc, but they all must allocate contiguous blocks of memory with no overlap.
Consider two calls to malloc.
char *foo = malloc(8);
char *bar = malloc(8);
And let's say foo and bar are allocated adjacent blocks of memory like so. (Note: there's no guarantee they will be adjacent and many reasons why they shouldn't be.)
0123456789abcdef0123456789abcdef
^^^^^^^^
| ^^^^^^^^
foo |
bar
Now you try to grow foo.
foo = realloc(foo, 16);
If realloc tries to keep the same pointer, foo would have to overlap into bar's memory.
0123456789abcdef0123456789abcdef
^^^^^^^^^^^^^^^^
| ^^^^^^^^
foo |
bar
That's not allowed, allocations cannot overlap. They also must be contiguous, so it cannot do this:
0123456789abcdef0123456789abcdef
^^^^^^^^ ^^^^^^^^
| ^^^^^^^^
foo |
bar
If it were allowed to do that, pointer math would not work. You would not be able to reliably add to foo to walk through its allocated memory.
So realloc must free foo and allocate a new block. (Again, no guarantee where it will be allocated.)
0123456789abcdef0123456789abcdef
^^^^^^^^
| ^^^^^^^^^^^^^^^^
bar |
foo
I need some explanation for some commands in this particular piece of code:
#inlcude <stdlib.h>
#define PTRS 5
char *p[PTRS];
size_t nbytes = 10;
int i;
/* Allocating memory */
for (i=0; i<PTRS; i++){
printf("malloc of %10lu bytes ", nbytes);
if ((p[i] = (char *)malloc(nbytes)) == NULL){
printf("failed\n");
} else {
printf("succeeded\n");
nbytes *= 100;
}
/* Free the memory allocated */
for (i=0; i<PTRS; i++){
if(p[i]){
free(p[i]);
p[i] = NULL;
}
}
First one is
char *p[PTRS];
Does this line declare a pointer to an array or does it declare an array of pointers to char?
p[i] = (char *)malloc(nbytes) I understand that as i increases, p[i] will contain a pointer to the allocated memory called by malloc if it's successfully processed, and p[i] will beNULL` if no such memory can be prepared.
Second one is
if (p[i]){
free(p[i]);
p[i] = NULL;
}
This only frees memory if p[i] has any value (in this case a pointer to the memory). What happens if we remove if(p[i]) and only use free(p[i] and p[i] = NULL? Can we free a NULL pointer?
char *p[PTRS];
is equivalent to
char *(p[PTRS]);
i.e. it's an array of pointers, not a pointer to an array. A pointer to an array would be e.g.
char (*p)[PTRS];
The clockwise/spiral rule could be helpful in deciphering declarations. As would using resource such as https://cdecl.org.
And you can pass a NULL pointer to free (it's a no-op) so the check isn't needed really.
Depending on the further use of p, the p[i] = NULL assignment might not be needed either.
I understand that as i increases, p[i] will contain a pointer to the
allocated memory called by malloc
So if you understand this when it means that p[i] being an element of an array has the type char * because at least in the program there is explicit casting to this type of themalloc call in the if statement
if ((p[i] = (char *)malloc(nbytes)) == NULL){
So this declaration
char *p[PTRS];
declares an array of PTRS elements with the tyoe char *. I advice to write such a declarations like
char * p[PTRS];
inserting a blank after the character '*'.
You may rewrite the declaration also the following way
char * ( p[PTRS] );
A pointer to an array of PTRS elements of the type char is declared the following way.
char ( *p )[PTRS];
Can we free a NULL pointer?
More precisely it would be said may we use the function free with a null-pointer because we are not freeing a null pointer itself that in the context of your example has the automatic storage duration.
The answer is yes we may. A call of the function with a null pointer will have neither affect and is safe.
Thus this loop
for (i=0; i<PTRS; i++){
if(p[i]){
free(p[i]);
p[i] = NULL;
}
}
may be rewritten like
for (i=0; i<PTRS; i++){
free(p[i]);
p[i] = NULL;
}
Consider char *a[] = {"abc", "xyz", "def"};
Deep copy char *a[] to char **b.
Can someone say what is deep copy? And how much memory we need assign to b?
char *a[n];
Is an array of n pointers-to-char. Each element of the array is contiguous in memory. The size in memory required is
sizeof(char *) * n
I've used the sizeof() operator here... you could assume 4 bytes for a pointer but this might not be safe... this depends on your hardware.
char **b
Is slightly different. This is a pointer to a point-to-char. **b has not allocated the array of pointers. First allocate the array...
char **b = malloc( sizeof(char *) * n);
EDIT: Thank you to interjay for pointing out my mistake... example below now uses strdup() to allocate the memory for each b[i]
**b points to the start of an array of n pointers. For each pointer in that array you could so do b[0] = a[0] for shallow copies
This is a shallow copy because b[0] will point to the same memory that a[0] points to. Thus changing the contents b[0] will change the contents of a[0].
A deep copy would imply that you have two totally independent entities... so changing the contents b[0] would not result in a change to the contents of a[0]. This means that for each b[i] you need to allocate new memory and copy the string from a[i] into that new block.
To deep copy:
char *a[n];
// ...intialise array a....
char **b = malloc( sizeof(char *) * n); // allocate array of pointers
if( b )
{
int i = 0;
for(; i < n; ++i)
b[i] = (char *)strdup(a[i]); // allocate memory for new string and copy string
}
else
printf("You ran out of memory!\n");
As an asside...
You've used constant strings so you shouldn't technically modify them...
char *xxx = "String";
char yyy[] = "String";
You can safely modify the contents of yyy. Normally you can modify the contents of xxx without any problem, but note, because the string memory is allocated at compile time, you could find that the compiler has, for example, placed it in read only memory.
EDIT:
There seems to have been debate on whether to cast return from malloc (which I've been in the habit of doing, but it seems this was a bad habit!)... see Why do we need to cast what malloc returns?
Walking on the a array, for eah a[i] request space to alloc it by using one of *alloc() family functions and put the result in the respective b[i]. The b pointers itself shall be a pointer with enough space for hold the number of string in a as pointers. Compute with something like this:
int bsize = (sizeof(a)/sizeof(a[0])) * sizeof(char*);
char **b = malloc(bsize);
int i,len;
/* if(b == NULL) /* error: no memory */
for(i = 0,len = sizeof(a)/sizeof(a[0]); i < len; i++) {
char *tmp = malloc(strlen(a[i])+1);
if(tmp == NULL) /* error: no memory */
strcpy(tmp, a[i]);
b[i] = tmp;
}
Note that you need to or hold the size of b array in memory either put a NULL at end of array.
You can just do
b=a
This will assign base address of array of pointers *a[3] to b.
Now you can access strings using b
for example string 1 can be accessed by *(b+0) gives address of string 1
string 2 " " *(b+1) " " string 2
string 3 " " *(b+2) " " string 3
Since you are assigning array of pointers to pointer to a pointer you are already assigning memory to b Hence you do not need to use malloc.
Only when you are assigning some data to a pointer at run time and you have not assigned memory to pointer in your program then only use malloc.