Problem with passing dynamic arrays by reference

T

Thomas Christmann

Hi!

Sorry for the weird topic, I don't know how to describe it better...
I have a little problem here I can't wrap my mind around. If I do:

-------------------------------------
#define DWORD unsigned long
#include <stdio.h>
#include <malloc.h>

int main(int argc, char* argv[])
{
DWORD *arr;
int i;

arr = malloc(sizeof(DWORD));
arr[0] = 1;
arr = realloc(arr,2*sizeof(DWORD));
arr[1] = 2;
for(i=0;i<=1;i++)
{
printf("%d\n",arr);
}
}
-------------------------------------

This works just fine, as expected. But when I try to do the allocation
and assignment inside a function, I get some (to me) strange behaviour.

-------------------------------------
#define DWORD unsigned long
#include <stdio.h>
#include <malloc.h>

void func(DWORD **arr)
{
*arr = malloc(sizeof(DWORD));
*arr[0] = 1;
*arr = realloc(*arr,2*sizeof(DWORD));
// crash here, as if trying to write to a bad ptr location
*arr[1] = 2;
}

int main(int argc, char* argv[])
{
DWORD *arr;
int i;

func(&arr);
for(i=0;i<=2;i++)
{
printf("%d\n",arr);
}
}
-------------------------------------

I'm sure it's quite easy and I just don't see it, but I just can't
figure out whats wrong with the code above. Can someone help me please?

Thanks,

Thomas

P.S.: Yes, I normally check for return values of malloc and realloc, I just
left it out of the post for brevity ;-)
 
J

Joona I Palaste

Thomas Christmann said:
Sorry for the weird topic, I don't know how to describe it better...
I have a little problem here I can't wrap my mind around. If I do:

<malloc.h> is a non-standard header and not needed in your entire
program. Use said:
int main(int argc, char* argv[])
{
DWORD *arr;
int i;

arr = malloc(sizeof(DWORD));
arr[0] = 1;
arr = realloc(arr,2*sizeof(DWORD));

This is dangerous. If realloc() fails to allocate more memory, it
keeps the original memory intact but returns NULL. You then end up
overwriting your previous pointer with NULL, which means both that
you've lost touch with your memory and the next line will cause
undefined behaviour.
Try this instead:
DWORD *arr, *tmp;
arr = malloc(sizeof(DWORD));
tmp = realloc(arr,2*sizeof(DWORD));
if (tmp != NULL) {
arr = tmp;
}
arr[1] = 2;
for(i=0;i<=1;i++)
{
printf("%d\n",arr);
}
}
-------------------------------------

This works just fine, as expected. But when I try to do the allocation
and assignment inside a function, I get some (to me) strange behaviour.

The same comments as above apply here.
I note with interest that you appear to have got the pointer-to-pointer
passing in the function right. This may surprise you, but many newbies
get it wrong on the first try, thinking that assigning to a parameter
changes the value of the original variable, as long as that parameter's
type is a pointer. You, however, are correctly assigning to what the
pointer parameter points to.
void func(DWORD **arr)
{
*arr = malloc(sizeof(DWORD));
*arr[0] = 1;
*arr = realloc(*arr,2*sizeof(DWORD));
// crash here, as if trying to write to a bad ptr location

Please also check if realloc() returns null here.
*arr[1] = 2;

I'm not too sharp on the C parsing rules, but I have a sneaky
suspicion that this is parsed as *(arr[1]) = 2, which will quite
obviously fail. Most likely if I'm wrong, Dan Pop will now tell me
to engage my brain and actually learn C. Just to be on the safe
side, try (*arr)[1] = 2.
int main(int argc, char* argv[])
{
DWORD *arr;
int i;

func(&arr);
for(i=0;i<=2;i++)
{
printf("%d\n",arr);
}
}
-------------------------------------

I'm sure it's quite easy and I just don't see it, but I just can't
figure out whats wrong with the code above. Can someone help me please?


P.S.: Yes, I normally check for return values of malloc and realloc, I just
left it out of the post for brevity ;-)

--
/-- Joona Palaste ([email protected]) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"The large yellow ships hung in the sky in exactly the same way that bricks
don't."
- Douglas Adams
 
A

Al Bowers

Thomas said:
But when I try to do the allocation
and assignment inside a function, I get some (to me) strange behaviour.

-------------------------------------
#define DWORD unsigned long
#include <stdio.h>
#include <malloc.h>

void func(DWORD **arr)
{
*arr = malloc(sizeof(DWORD));
*arr[0] = 1;
*arr = realloc(*arr,2*sizeof(DWORD));
// crash here, as if trying to write to a bad ptr location
*arr[1] = 2;
}

Other(s) have described the cause of your chief compliant. It
is a precedence and order of evaluation problem that is solved by
changing:
*arr[0] = 1;
to
(*arr)[0] = 1;
and changing:
*arr[1] = 2;
to
(*arr)[1] = 2;


int main(int argc, char* argv[])
{
DWORD *arr;
int i;

func(&arr);
for(i=0;i<=2;i++)
{
printf("%d\n",arr);


By the way, with printf, the correct specifier for
unsigned long, (DWORD), is %lu not %d.
 
M

Martin Ambuhl

Thomas said:
... But when I try to do the allocation
and assignment inside a function, I get some (to me) strange behaviour.
#define DWORD unsigned long
#include <stdio.h>
#include <malloc.h>
void func(DWORD **arr)
{
*arr = malloc(sizeof(DWORD));
*arr[0] = 1;
*arr = realloc(*arr,2*sizeof(DWORD));
// crash here, as if trying to write to a bad ptr location
*arr[1] = 2;
}
int main(int argc, char* argv[])
{
DWORD *arr;
int i;

func(&arr);
for(i=0;i<=2;i++)
{
printf("%d\n",arr);
}
}

I'm sure it's quite easy and I just don't see it, but I just can't
figure out whats wrong with the code above. Can someone help me please?

Note the output for the locations:

#include <stdio.h>
#include <stdlib.h> /* mha: was <malloc.h> */

void func(unsigned long **arr)
{
unsigned long *tmp;
*arr = malloc(sizeof(unsigned long));
*arr[0] = 1;
tmp = realloc(*arr, 2 * sizeof(unsigned long));
if (tmp)
*arr = tmp;
/* mha: a poor way to handle error, but WTF */
else {
*arr = 0;
return;
}
(*arr)[1] = 2; /* mha: was '*arr[1] = 2;/ */
printf("value of *arr %p\n" "address of (*arr[1]) %p\n"
"address of ((*arr)[1]) %p\n", (void *) (*arr),
(void *) &(*arr[1]), (void *) &((*arr)[1]));
}

int main(void)
{
unsigned long *arr;
int i;

func(&arr);
if (arr)
for (i = 0; i <= 2; i++)
printf("%ld\n", arr); /* mha: changed "%d" to "%ld" */
return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top