Jump to content
Can't remember your login details? Read more... ×
robzy

C malloc an array of pointers

Recommended Posts

So I'm trying to create an array of pointers, but the number of pointers I need in this array will only been known at compile time. For the moment, though, I'm using a constant...

 

int **tehnumbers;
int *anumber

tehnumbers = (int **)malloc(5*sizeof(int*));
anumber = (int *) malloc(sizeof(int));

(*tehnumbers)[0] = anumber

However on that very last line, I'm getting...

 

incompatible types in assignment

I'm likely allowing my lack of C knowledge let me get very confused, any suggestions? It works if I don't use *tehnumbersas an array...

 

*tehnumbers = anumber;

... is there something wrong with how I've defined tehnumbers?

 

Rob.

Edited by robzy

Share this post


Link to post
Share on other sites

Okay, so after mucking around with cdecl ( http://cdecl.ridiculousfish.com/?q=cast+te...+pointer+to+int ) I came up with this, which seems to work...

 

int *(*tehnumbers)[];
int *anumber

tehnumbers = (int*(*)[])malloc(5*sizeof(int*));
anumber = (int *) malloc(sizeof(int));

(*tehnumbers)[0] = anumber
(*tehnumbers)[1] = anumber
(*tehnumbers)[2] = anumber
(*tehnumbers)[3] = anumber
(*tehnumbers)[4] = anumber

Can anyone see anything with with that? *fingers crossed no*

 

And what do I make of cdecl telling me that what I'm doing is unsupported in C? :S

 

Rob.

Share this post


Link to post
Share on other sites

I haven't played around with __cdecl, but I can tell you what's happening in your first post.

 

1. Declaring an array of pointers.

int **tehnumbers;
This is correct.

 

2. Malloc for the pointer to pointers and the pointers themselves.

These look fine too.

 

3. Assigning the pointers to each of the elements in the array of pointers.

Heres the first trouble:

(*tehnumbers)[0] = anumber;
Here you're dereferencing the first element in your unintialised array of pointers to ints and trying to assign it the value of the individual pointer. Expect a segfault. The correct way to do this is:

tehnumbers[0] = anumber;

4. Finally making use of the array of pointer to ints:

*tehnumbers[n]
would first get the n-th int pointer in the array, then dereference it to get you the actual int.

Share this post


Link to post
Share on other sites

I think the bigger problem is that the code in your second post is logically wrong.

I think you may need to read up on malloc again ... http://en.wikipedia.org/wiki/Malloc#Dynami...allocation_in_C

If the allocation succeeds, a pointer to the block of memory is returned which is guaranteed to be suitable aligned to any type

You call malloc, and return the result to anumber, this is now a pointer to location in memory - you then assign this pointer to all five spots in the 'array'.

 

 

Second to that, is the reason why your getting the problem in the first code.

By using (*tehnumber), you are dereferencing the pointer to a value, in this case a pointer to an 'array', not really an array but another pointer...

You then call [0] on this other pointer, which again is a dereference to a spot in memory which should contain in INT, and then you try to assign a pointer to an int to it... ;-)

 

For help, try looking over the code in these:

 

http://www.lysator.liu.se/c/c-faq/c-2.html

Section 2.14 - I actually like the third method of only doing a single malloc, and then using arithmetic to handle the multidimensional indexing.

 

http://www.eskimo.com/~scs/cclass/int/sx9b.html

 

In any case, it is important that you have a loop to call malloc for each of the second level elements! ;-)

Share this post


Link to post
Share on other sites

3. Assigning the pointers to each of the elements in the array of pointers.

Heres the first trouble:

(*tehnumbers)[0] = anumber;
Here you're dereferencing the first element in your unintialised array of pointers to ints and trying to assign it the value of the individual pointer. Expect a segfault. The correct way to do this is:

tehnumbers[0] = anumber;
That couldn't be the correct way? tehnumbers[0] is a "pointer to a pointer to an int", isn't it? And anumber is a "pointer to an int", therefore that assignment doesn't make any sense, does it?

 

I think the bigger problem is that the code in your second post is logically wrong.

I do have reasons for wanting to do it this way. I need an array of pointers on the heap, and this is the only way to do it.

 

Second to that, is the reason why your getting the problem in the first code.

By using (*tehnumber), you are dereferencing the pointer to a value, in this case a pointer to an 'array', not really an array but another pointer...

You then call [0] on this other pointer, which again is a dereference to a spot in memory which should contain in INT, and then you try to assign a pointer to an int to it... ;-)

Ohh... does [] dereference a pointer?? That would explain where I'm going wrong.

 

Rob.

Share this post


Link to post
Share on other sites

Ohh... does [] dereference a pointer?? That would explain where I'm going wrong.

That's correct. Consider this example:

 

int *foo = (int *) malloc(10 * sizeof(int)); // Allocate space for 10 ints.

// Set the elements to values 0 to 10.
for (int i = 0; i < 10; ++i)
{
  foo[i] = i;
}

The pointer we get from malloc() is foo.

 

foo gets the i-th element in that array.

&foo[0] has the same value as foo, which is the pointer to the 0-th element.

 

Oh, and don't forget to check (foo == NULL) for when memory allocation fails.

Edited by edmund.tse

Share this post


Link to post
Share on other sites

Ahh, I see! I didn't realise that 'automatically' dereferences a pointed.

 

&foo[0] has the same value as foo, which is the pointer to the 0-th element.

And what about &foo[1]?

 

Rob.

Share this post


Link to post
Share on other sites

So I might've been a tad sceptical edmund, but I just attacked your code with GDB and it seems to be doing exactly what it should. Thanks muchly!

 

And I know I should be checking malloc for return values, but for the moment I'm just trying to quickly learn-by-doing an algorithm, it isn't a program with a practical purpose at all.

 

(Yet, that is. But when I do turn it into a practical purpose it will be by a total rewrite.)

 

Rob.

Share this post


Link to post
Share on other sites

And what about &foo[1]?

That would give the pointer with the value of (foo + 1), the pointer to the 1-th (second) element in the array.

Share this post


Link to post
Share on other sites

And what about &foo[1]?

That would give the pointer with the value of (foo + 1), the pointer to the 1-th (second) element in the array.

 

Oh I see. When you realise that [] automatically dereferences a pointer it does start to make sense.

 

Thanks a lot for the help, not only did you solve my problem, but you've taught me a lot in the process :)

 

And thanks for the link ozacube, looks interesting.

 

Rob.

Share this post


Link to post
Share on other sites

1. p is short for *(p+i), so "steve"[2] is valid :)

 

2. use malloc as follows:

 

ptr = malloc(sizeof(*ptr)*N);

This style means that if you change the type of ptr you don't need to change the cast or the sizeof, making maintenance less error prone.

 

3. consider using calloc in future.

 

4. don't doubt edmund :P

Edited by freespace

Share this post


Link to post
Share on other sites

int **tehnumbers;
int *anumber

(*tehnumbers)[0] = anumber

However on that very last line, I'm getting...

 

incompatible types in assignment

Yep, they are incompatible. On the left you have an int, on the right, you have a int*. Perhaps you meant to dereference anumber?

 

Try:

(*tehnumbers)[0] = *anumber;

Share this post


Link to post
Share on other sites

2. use malloc as follows:

 

ptr = malloc(sizeof(*ptr)*N);

This style means that if you change the type of ptr you don't need to change the cast or the sizeof, making maintenance less error prone.

That's a pretty darn good idea :P Thanks. (And as a point of note, I wasn't actually using ints, but instead nodes in a binary tree)

 

3. consider using calloc in future.

The reason I went malloc is because I am realloc too, so to keep things (arguments) uniform I am using malloc. (Although a quick google suggests there might actually be a recalloc)

 

4. don't doubt edmund :P

Lesson learnt :P

 

Rob.

Share this post


Link to post
Share on other sites

Just on pointers, it can be quite handy to have your own allocate and deallocate functions. For example, you could return a boolean to indicate a successful/unsuccessful allocation, on allocation automatically check and reallocate/deallocate reused pointers, and when deallocating, set the pointer values to null, (good practice to ensure that invalid reuse does not occur).

Edited by Periander

Share this post


Link to post
Share on other sites

void* calloc(size_t nmemb, size_t size) {
	void* ptr = malloc(nmemb*size);
	if (ptr)
		memset(ptr, 0, nmemb*size);
	return ptr;
}

What's the bet that's the implementation of calloc? You can certainly realloc a region allocated using calloc, is basically equivalent to using malloc, then immediately memsetting it to zero.

Edited by Redhatter

Share this post


Link to post
Share on other sites

What's the bet that's the implementation of calloc? You can certainly realloc a region allocated using calloc, is basically equivalent to using malloc, then immediately memsetting it to zero.

I'm sure that I could realloc a region of memory allocated using calloc... but my code is more uniform (in terms of arguments used) if I stick to malloc.

 

You're right, I could've saved some typing by using calloc, but why shuffle that calculation away when it's needing to be made with realloc anyway. I decided to lean towards code uniformity.

 

Rob.

Edited by robzy

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×