I'm looking for a smart way to copy a multidimensional char array to a new destination. I want to duplicate the char array because I want to edit the content without changing the source array.
I could build nested loops to copy every char by hand but I hope there is a better way.
Update:
I don't have the size of the 2. level dimension. Given is only the length (rows).
The code looks like this:
char **tmp;
char **realDest;
int length = someFunctionThatFillsTmp(&tmp);
//now I want to copy tmp to realDest
I'm looking for a method that copies all the memory of tmp into free memory and point realDest to it.
Update 2:
someFunctionThatFillsTmp() is the function credis_lrange() from the Redis C lib credis.c.
Inside the lib tmp is created with:
rhnd->reply.multibulk.bulks = malloc(sizeof(char *)*CR_MULTIBULK_SIZE)
Update 3:
I've tried to use memcpy with this lines:
int cb = sizeof(char) * size * 8; //string inside 2. level has 8 chars
memcpy(realDest,tmp,cb);
cout << realDest[0] << endl;
prints: mystring
But I'm getting a: Program received signal: EXC_BAD_ACCESS
As others suggested, it looks like this is an array of pointers rather than a multi demetional array.
so instead of it being
char mdArray[10][10];
it is:
char* pArray[10];
if that is the case the only thing you can do is loop through with the one length value you get, if there are meant to be strings (which it looks like it is) then use strlen in which case it would be:
You could use
memcpy
.If the multidimensional array size is given at compile time, i.e
mytype myarray[1][2]
, then only a single memcpy call is neededIf, like you indicated the array is dynamically allocated, you will need to know the size of both of the dimensions as when dynamically allocated, the memory used in the array won't be in a contiguous location, which means that memcpy will have to be used multiple times.
Given a 2d array, the method to copy it would be as follows:
Given that from your question it looks like you are dealing with an array of strings, you could use strlen to find the length of the string (It must be null terminated).
In which case the loop would become
You can just calculate the overall size of the array and then use memcpy to copy it.
Edit: new information in the question indicates that the number of rows and cols of the array is not known, and that the array may be ragged, so memcpy may not be a solution.
Why are you not using C++?
Or something similar? Also, do you need to use C-strings? I doubt it.
When you have a pointer to a pointer in C, you have to know how the data is going to be used and laid out in the memory. Now, the first point is obvious, and true for any variable in general: if you don't know how some variable is going to be used in a program, why have it? :-). The second point is more interesting.
At the most basic level, a pointer to type
T
points to one object of typeT
. For example:Now,
pi
points to oneint
. If you wish, you can make a pointer point to the first of many such objects:pa
now points to the first of a sequence of 10 (contiguous)int
values, and assuming thatmalloc()
succeeds,pb
points to the first of another set of 10 (again, contiguous)int
s.The same applies if you have a pointer to a pointer:
Assuming that
malloc()
succeeds, now you haveppa
pointing to the first of a sequence of 10 contiguousint *
values.So, when you do:
tmp
points to the firstchar *
object in a sequence ofCR_MULTIBULK_SIZE
such objects. Each of the pointers above is not initialized, sotmp[0]
totmp[CR_MULTIBULK_SIZE-1]
all contain garbage. One way to initialize them would be tomalloc()
them:The
...
above is the size of thei
th data we want. It could be a constant, or it could be a variable, depending uponi
, or the phase of the moon, or a random number, or anything else. The main point to note is that you haveCR_MULTIBULK_SIZE
calls tomalloc()
in the loop, and that while eachmalloc()
is going to return you a contiguous block of memory, the contiguity is not guaranteed acrossmalloc()
calls. In other words, the secondmalloc()
call is not guaranteed to return a pointer that starts right where the previousmalloc()
's data ended.To make things more concrete, let's assume
CR_MULTIBULK_SIZE
is 3. In pictures, your data might look like this:tmp
points to a contiguous block of 3char *
values. The first of the pointers,tmp[0]
, points to a contiguous block of 3char
values. Similarly,tmp[1]
andtmp[2]
point to 5 and 2char
s respectively. But the memory pointed to bytmp[0]
totmp[2]
is not contiguous as a whole.Since
memcpy()
copies contiguous memory, what you want to do can't be done by onememcpy()
. Further, you need to know how eachtmp[i]
was allocated. So, in general, what you want to do needs a loop:As above, you can call
memcpy()
inside the loop, so you don't need nested loop in your code. (Most likelymemcpy()
is implemented with a loop, so the effect is as if you had nested loops.)Now, if you had code like:
I.e., you allocated contiguous space for all the pointers in one
malloc()
call, then you can copy all the data without a loop in your code:From the above, the simple answer is, if you had more than one
malloc()
to allocate memory fortmp[i]
, then you will need a loop to copy all the data.Lets explore some possibilities for what's going on here:
The moral of the story is: you must to know what is on the other side of your pointers. Or else.
The second moral of the story is: just because you can access a double pointer using the
[][]
notation does not make it is the same as two-dimensional array. Really.Let me clarify the second moral a little bit.
An array (be it one dimensional, two dimensional, whatever) is an allocated piece of memory, and the compiler knows how big it is (but never does any range checking for you), and a what address it starts. You declare arrays with
and similar things;
A pointer is a variable that can hold a memory address. You declare pointers with
They are two different things.
But:
[]
syntax with a pointer, the compiler will do pointer arithmetic for you.So, I can do
because rule 2 says that string1 (an array) is treated as a
char*
). Likewise, I can fllow that with:Finally,
will print "OK" because of rule 1.