tags:

views:

151

answers:

2

see this example:

 int *array = malloc (10 * sizeof(int)) 

Then free only the first 3 blocks?

Or make equal java, have an array with negative index, or an index that not began with 0.

Thanks a lot.

+3  A: 

You can't free part of an array - you can only free() a pointer that you got from malloc() and when you do that, you'll free all of the allocation you asked for.

As far as negative or non-zero-based indices, you can do whatever you want with the pointer when you get it back from malloc(). For example:

int *array = malloc(10 * sizeof(int));
array -= 2;

Makes an array that has valid indices 2-11. For negative indices:

int *array = malloc(10 * sizeof(int));
array += 10;

Now you can access this array like array[-1], array[-4], etc.

Be sure not to access memory outside your array. This sort of funny business is usually frowned upon in C programs and by C programmers.

Carl Norum
The `array -= 2;` is undefined behavior, IIRC, since it forms a pointer value that neither points to valid memory nor is one past the end of some valid memory. This usually isn't a problem with modern computers, but there are systems (like the old Boehm conservative garbage collector) that will have problems with this.
David Thornley
+1 for making me stop and think - even though I most definitely am frowning too.
Steve314
@David - the Boehm conservative garbage collector has problems with a lot of things. Anyone who uses it will be adjusting their idioms to suit, but that doesn't mean everyone has to do the same. GC is not part of the standard C language. Pointer arithmetic is everyday stuff in C - dereferencing the pointer when it points to something that doesn't exist is obvious undefined behaviour, but simply having an out-of-range pointer stored somewhere? I'd be more than surprised if that is undefined behaviour.
Steve314
@Steve, what David said is right. It is undefined to point outside of allocated memory, except for one past the end which is allowed. You don't even have to dereference the pointer.
John Kugelman
@John - OK - +1 that comment for surprising me.
Steve314
If your compiler/system really can't handle the subtraction, just cast to `intptr_t` and throw it around that way.
Carl Norum
@Steve314: with a lot of these "why the heck is this undefined behaviour?" questions, it can help to imagine an architecture where only valid values can be loaded into a register. The standard talks about "trap representations", which means bit patterns in memory that, if used, cause undefined behaviour. You don't expect that any more for integers and pointers, but you might for floats. The same principle motivates the idea that `array-2` is undefined behaviour - C aims to permit implementation on architectures where a pointer register is physically incapable of holding an invalid pointer.
Steve Jessop
+9  A: 

You can't directly free the first 3 blocks. You can do something similar by reallocating the array smaller:

/* Shift array entries to the left 3 spaces. Note the use of memmove
 * and not memcpy since the areas overlap.
 */
memmove(array, array + 3, 7);

/* Reallocate memory. realloc will "probably" just shrink the previously
 * allocated memory block, but it's allowed to allocate a new block of
 * memory and free the old one if it so desires.
 */
int *new_array = realloc(array, 7 * sizeof(int));

if (new_array == NULL) {
    perror("realloc");
    exit(1);
}

/* Now array has only 7 items. */
array = new_array;

As to the second part of your question, you can increment array so it points into the middle of your memory block. You could then use negative indices:

array += 3;
int first_int = array[-3];

/* When finished remember to decrement and free. */
free(array - 3);

The same idea works in the opposite direction as well. You can subtract from array to make the starting index greater than 0. But be careful: as @David Thornley points out, this is technically invalid according to the ISO C standard and may not work on all platforms.

John Kugelman
I would modify your first sentence as "You can't directly free the first 3 blocks *unless you allocate each block individually*". You can allocate (in this example) 10 separate blocks and store pointers to the blocks in an array (no guarantee that the blocks will be physically contiguous, though).
bta
As you said in your first answer, when I realloc the array and gave only 7 blocks, my array will begin in which index? 3 or 0? If the first one is correct, how can I begin my array in the 3 index without allocate mem for the 0 1 n 2 index?
drigoSkalWalker
Why do you want to do this? There's probably a better way to do whatever you're trying to do. Changing the base index of an array is an unusual request.
John Kugelman