array arithmetic - pointer types indexing - c

In my previous question:
Pointer dereference array index I have asked about struct being dereferenced. (I will paste a snippet of code from there for recap):
#include <stdio.h>
#include <stdlib.h>
struct Test { char c; } foo;
int main (void) {
struct Test **ar;
ar=malloc(16);
*ar=malloc(0); //prerequisite for second case (without getting some address from OS, I cannot go 'through' *ar to (*ar+1).
//Does not matter allocation of zero bytes. (only to get some valid address)
*(ar+1) = &foo;
//(**(ar+1)).c='c'; //// first case - works
(*(*ar+1)).c='c'; //// second case - also works, with prerequisite
printf("%c\n", (*(*ar+1)).c); //prints 'c'
return 0;
}
I still do understand between pointer adding +1 in first vs second case. Well I do in the second - adding sizeof(struct Test*) to the address *ar, which like array indexing (so *ar is name pointer of array). But in the first case? what does (**(ar+1)) do? How can I add (what?) some kind of pointer type sizeof(struct Test**) when ar is not array? *(ar+1) dereference address that does not belong to me, but (*ar+1) dereference address of pointer (sizeof(struct Test*)) that DOES belong to me (an array member). So why does the first case work? (from the link, I am trying to give my understanding by resolving type being indexed [ e.g. - in first case a "step/index" is made by sizeof(struct Test**) and in second case by sizeof(struct Test*), but both have same size) - just take a look at the link.

So why does the first case work?
(**(ar+1)).c='c' doesn't work at all on my specific system.
(**(ar+1)) performs pointer arithmetic on a struct Test ** type, and (*(*ar+1)) performs pointer arithmetic on a struct Test* type.
This means that in the former case, arithmetic is done by sizeof(struct Test *) bytes, in the latter case on sizeof(struct Test) bytes.
The compiler might add padding inside your struct so that it ends up as 4 bytes etc, whatever size a pointer happens to be on your system. So they might end up at the same address by luck. Pointer sizes are commonly 2, 4 or 8 bytes, depending on if a 16, 32 or 64 bit address bus is used.
It is not very meaningful to ponder about what obscure code like this does. Explicit pointer arithmetic in general should be avoided, it is much better practice to use the [] operator to get readable code.
Also please note that malloc(0) gives "either a null pointer
is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object." If you get a null pointer and then attempt arithmetic, you have undefined behavior and anything might happen.

So let's break up your code:
Declaring a pointer to pointer to struct Test.
struct Test **ar;
Allocating space for pointers, if your system is 64 bits you are allocating space for exactly 2 contiguous pointers.
ar = malloc(16);
Allocating memory block and assigning it to the first pointer (arr[0] = malloc(0)), this is never used, but without compiler optimization you still need to initialize it, allocating 0 bytes might not be the best option since it invokes undefined behaviour but since you never store anything there it doesn't cause problems.
*ar = malloc(0);
You are storing foo address in pointer number 2, which, since it works, leads me to believe that your system is indeed 64 bits.
*(ar+1) = &foo;
Works, assigning 'c' to char c to one past the foo struct. The same as ar[0][1].c ='c';
(*(*ar+1)).c = 'c';
printf("%c\n", (*(*ar+1)).c); //prints 'c'
The out of bounds accesses work because in C one past the end of an array or allocated memory block is available, and it looks like your implementation let's you access it to write and dereference, though it's out of bounds, mine too by the way, this is not always true so you can't expect it to always work.
This all works by chance (or maybe not), because you allocate the needed space for the 2 pointers.
Now lets make some changes to you allocation to compare with what you have, and let's mess around with the structure's paddings to store and access values out of the bounds of the allocated memory.
#include <stdio.h>
#include <stdlib.h>
struct Test
{
char c;
} foo;
int main(void)
{
struct Test **ar; //declaring a pointer to pointer to struct Test
ar = malloc(sizeof(*ar) * 2); //allocation of space for 2 pointers to struct Test.
//without optimization you still need to allocate space
//or otherwise initialize the 1st pointer to avoid UB
*(ar + 0) = malloc(sizeof(**ar)); //or ar[0] = ... or *ar = ...
*(ar + 1) = &foo; //or ar[1] = ... storing foo's address in the second pointer
(*(*ar + 1)).c = 'c'; //works fine, one past the allocated memory
printf("%c\n", ar[0][1].c);
(**(ar + 1)).c = 'b'; //works, actually foo
printf("%c\n", ar[1][0].c);
(*(*(ar + 1) + 1)).c = 'a'; //also works, accessing ou of bounds
printf("%c\n", ar[1][1].c);
printf("%c\n", foo.c); //test print foo
return 0;
}
Live demo
This is much better not only in terms of readability but also in terms of portability since is the systems who decides what's the size of the pointers.
Now look at this simplified code:
#include <stdio.h>
#include <stdlib.h>
struct Test
{
char c;
} foo;
int main(void)
{
struct Test** ar;
ar = malloc(sizeof(*ar) * 2);
ar[0] = malloc(sizeof(**ar)); //or *ar = ...
ar[1] = &foo; //or *(ar + 1) = ...
ar[0]->c = 'a';
printf("%c\n", ar[0]->c);
ar[1]->c = 'c';
printf("%c\n", ar[1]->c);
printf("%c\n", foo.c); //ok foo has 'c'
return 0;
}
Look how easy it is to use double pointers if one doesn't overcomplicate things.

Related

How do I properly allocate an array within a struct with malloc and realloc in C?

I'm trying to implement a stack in C, while also trying to learn C. My background is mostly in higher languages (like Python), so a lot of the memory allocation is new to me.
I have a program that works as expected, but throws warnings that make me believe I'm doing something wrong.
Here is the code:
typedef struct {
int num_items;
int top;
int items[];
} stack;
void push(stack *st, int n) {
st->num_items++;
int* tmp = realloc(st->items, (st->num_items) * sizeof(int));
if (tmp) {
*(st->items) = tmp;
}
st->items[st->num_items - 1] = n;
st->top = n;
}
int main() {
stack *x = malloc(sizeof(x));
x->num_items = 0;
x->top = 0;
*(x->items) = malloc(0);
push(x, 2);
push(x, 3);
printf("Stack top: %d, length: %d.\n", x->top, x->num_items);
for (int i = 0; i < x->num_items; i++) {
free(&(x->items[i]));
}
free(x->items);
free(x);
}
Here is the output:
Stack top: 3, length: 2.
Which is expected. But during compilation, I get the following errors:
> gcc -x c -o driver driver.c
driver.c: In function 'push':
driver.c:16:16: warning: assignment makes integer from pointer without a cast
*(st->items) = tmp;
...
driver.c: In function 'main':
driver.c:27:14: warning: assignment makes integer from pointer without a cast
*(x->items) = malloc(0);
When you have an empty array declared at the end of the structure like you have, it's called a flexible array member. And you allocate it not by allocating just the array member, but by allocating the whole structure.
Like e.g.
stack *x = malloc(sizeof *x + sizeof s->items[0] * 32);
The above malloc call allocates space for the structure itself (note the use of the dereference operator for sizeof *x) plus space for an array of 32 elements.
It's either the above, or change the member to be a pointer.
This is an array of unspecified size
int items[];
This is a pointer
int *items;
The latter is what you use with malloc/realloc to make use of dynamically allocated memory.
Also, because you're doing (for example)
*(x->items) = malloc(0);
...you're de-referencing items so that it becomes an int which is why you're getting those particular warnings.
Your belief is correct. Usually - that is almost always - warnings from C compiler are signs of grave programming errors that will cause serious problems. Quoting Shooting yourself in the foot in various programming languages:
C
You shoot yourself in the foot.
You shoot yourself in the foot and then nobody else can figure out what you did.
The problem is that you're coding as if items was a pointer to int, yet you have declared and defined it as a flexible array member (FAM), which is an entirely different beast altogether. And since assigning to an array would produce an error, i.e.
x->items = malloc(0);
would be an error, you've come up with something that compiles with just warnings. Remember that errors are better than warnings, because they stop you from shooting yourself into foot.
The solution is to declare items as a pointer to int instead:
int *items;
and use
x->items = ...;
to get the pointer behaviour you expect.
Also,
free(&(x->items[i]));
is very wrong, since you never allocated the ith integer to begin with; they were objects in the array. Also, you don't need malloc(0); just initialize with a null pointer:
x->items = NULL;
realloc and free wouldn't mind the null pointer.
The flexible array member means that the last element in the structure is an array of indefinite length, so in malloc you would reserve enough memory for it too:
stack *x = malloc(sizeof x + sizeof *x->items * n_items);
The flexible array member is used in CPython for objects like str, bytes or tuple that are of immutable length - it is slightly faster to use a FAM instead of a pointer elsewhere, and it saves memory - especially with shorter strings or tuples.
Finally, notice that your stack becomes slower the more it grows - the reason is because you're always allocating just one more element. Instead, you should scale the size of the stack by a factor (1.3, 1.5, 2.0?), so that insertions run in O(1) time as opposed to O(n); and consider what will happen should realloc fail - perhaps you should be more loud about it!

Check if a pointer points to a valid structure

I have N statically allocated structures.
struct exemple{
...
}
struct exemple array[N];
struct exemple *test_ptr = 0x3; /* random address */
Can I check if test_prt points to a valid address? i.e. it points to one "struct example" allocated.
You can't. You have to know. It's not a problem if you manage your pointers correctly. A good habit is to always set pointers to 0 / NULL as soon as you destroy the object they point to. Then you can just test with if (ptr) or if (!ptr) (or, more verbose: if (ptr == NULL) / if (ptr != NULL)).
Note that your last assignment
struct exemple *test_ptr = 0x3; /* random address */
is invalid. you can't assign an integer to a pointer. but you can cast it to the pointer type;
struct exemple *test_ptr = (struct exemple *)0x3; /* random address */
The result will depend on your implementation / system.
You can only check if pointer is valid by doing pointer != NULL because anything except `NULL' is treated by valid pointer.
In your case, to check if your pointer points to any of your array entry, you can only do this:
size_t i = 0;
int isValid = 0;
for (i = 0; i < N; i++) {
if (test_ptr == &array[i]) {
isValid = 1;
break;
}
}
if (isValid) {
//Pointer points to one of your array entry
}
But in general, you cannot just test if pointer points to specific valid location for you. It is up to you to take care of where it points. It can also have NON-NULL value but points to invalid location, for example:
int* ptr = malloc(10); //Now points to allocated memory
*ptr = 10;
free(ptr); //Free memory
*ptr = 10; //Undefined behaviour, it still points to the same address but
//we don't know what will happen. Depends on implementation
In general, no, you can't test if a pointer is valid or not.
But, if you want to know if a pointer points to an element of an array, you can:
if(test_ptr >= &array[0] && test_ptr < &array[N]
&& ((intptr_t)test_ptr - (intptr_t)array)%((intptr_t)(&array[1]) - (intptr_t)array) == 0) {
// test_ptr points to an element of array
}
This works because arrays are allocated contiguously.
There is no language method but in some circumstances you can try to have some known values at the certain points of the structure. If the pointed memory location has those values you can assume it as valid - but of course you do not have any guarantee. But you need to write your own functions when you create the structure, and when you destroy it (by filling with zeros before freeing the memory). It is a very week workaround - but if you connect with another measures and accept the overhead it makes the probability of the incorrect program behaviour lower.
Sometimes it is called a security cookie.
it is possible of course to make it more complicated - at certain positions you have only offsets to those cookies. It makes less probable that the random position in the memory will have such a chain of data :)
I don't know if I get your question properly.
If you want to know if a pointer points to a struct of some type (cast my structs to void * and vice-versa, for example), I do the next way:
#include <assert.h>
struct my_struct {
#ifndef NDEBUG
#define MY_STRUCT_MAGIC 0x1234abcd
uint64_t magic;
#endif
int my_data;
};
void init_struct(struct my_struct *s, int t_data) {
#ifdef MY_STRUCT_MAGIC
s->magic = MY_STRUCT_MAGIC;
#endif
s->my_data = t_data;
}
my_struct *my_struct_cast(void *vs) {
my_struct *s = vs;
#ifdef MY_STRUCT_MAGIC
assert(MY_STRUCT_MAGIC == s->magic);
#endif
return s;
}
It has a little bit more code because of inclusion of const-casting, but I think you get the idea.
If you want to know if test_ptr points to a aray member, you have to check this way: test_ptr >= array && test_ptr < &array[sizeof(array)/sizeof(array[0])]). If the pointer comes from void, char, or some kind of dangerout ariyhmetic, you could also check for test_ptr % sizeof(array[0])
If you want to know if a pointer points to valid memory "ever allocated" by your program, you will have to intercept allocs functions, save returned chunks pointer & size, and compute like the previous example.

free struct of unions in c

I have a dynamically allocated vector of a special struct, and i trying to free but the software always crashes
the structure is :
typedef struct {
Type_e type;
union {
char m_char;
int m_int;
// more types (non of them is a pointer)
} my_data;
} Data_t;
where Type is an enum that contain all possible data types.
I allocate and initialize the vector as follows
void vector(Data_t **vec, UInt32_t start_element, UInt32_t end_element, Type_e type)
{
UInt32_t i;
Data_t *vec_ptr;
*vec=(Data_t *)malloc((size_t) ((end_element-start_element+1) * sizeof(Data_t)));
vec_ptr = *vec;
if (!vec_ptr)
{
// Write error
}
for (i =start_element; i <= end_element + 1; i++)
{
vec_ptr->type = type;
switch (type)
{
case UINT32: vec_ptr->my_data.m_int = 0; break;
// more possible cases
default:
break;
}
(vec_ptr)++;
}
}
I call this function as follows
Data_t *lVector = NULL;
vector(&lVector,0,10,INT32)
but when I try to free the allocated memory as follows,
free (lVector+start_element-1);
I tried
free (lVector+start_element);
and
free (lVector);
were start_element = 0 (in this case)
But in all cases, it crash. Am I doing anything wrong ?
This is incorrect:
*vec = *vec + sizeof(Data_t);
It advances *vec by sizeof(Data_t)*sizeof(Data_t) bytes, because pointer arithmetics multiplies integral constants by sizeof(*p) automatically.
Replace with (*vec)++, and let the compiler do the math for you. Similarly, remove multiplication in all places where you manipulate pointers. The only place in your code where you need to multiply by sizeof is when you call malloc.
Note: your code is hard to read because you move *vec back and forth as you go through the loop. You would be better off declaring and using a plain temporary pointer for iterating the vector, and keeping *vec fixed to whatever has been allocated by malloc.
You must free exactly the pointer returned by malloc, and do so exactly once. You store the return value of malloc in *vec, so free(*vec) would be correct in the same function or free(lVector) in the calling function. However, you subsequently assign other values to *vec, so to be able to free it correctly you would need to somehow restore the original return value of malloc (a better choice would almost certainly be to use another variable instead).
You also seem to misunderstand pointer arithmetic. p += n already advances the address pointed to by sizeof(*p) * n. So you mustn't multiply the changes to *vec by sizeof(Data_t) (which is sizeof(**vec)).
this parameter says array of pointers to type 'Data_t'
Data_t **vec,
however, this line:
*vec=(Data_t *)malloc((size_t) ((end_element-start_element+1) * sizeof(Data_t)));
allocates memory for an array of 'Data_t' not an array of pointers to 'Data_t'
in C, do not cast the returned value from malloc
the parameter to malloc() is automatically a 'size_t' so casting to 'size_t' just clutters the code
This line:
for (i =start_element; i <= end_element + 1; i++)
iterates over the array from index 0 to index 11 however, the valid index is from 0 to 10 as C array indexs start with 0 and end at sizeof(array) -1
this line:
(*vec)->type = type;
is expecting 'vec' to actually be an array of pointers to struct. But, as mentioned earlier, it is not
this line:
*vec = *vec + sizeof(Data_t);
is properly stepping through the array of struct However, this looses the pointer to the malloc'd memory, resulting in a memory leak because the pointer to malloc'd memory is lost so cannot be passed to free()
This line:
*vec = *vec - ((end_element-start_element+1) * sizeof(Data_t));
doesn't quite work, because the prior 'for' statement iterates one too many times.
Strongly suggest indexing off 'vec' rather than changing vec contents. I.E. vec[i]
Where do you try to call free()?
If inside vector(), you will free '&lVector', which's on the Stack and can't be freed.
You can only free space you allocated with malloc(), so you can free *vec, but not vec.

Freeing a pointer in a structure referenced by a pointer

I have a pointer to several structures that have been allocated memory via:
STRUCTNAME *ptr;
ptr = (STRUCTNAME *)malloc(sizeof(STRUCTNAME)*numberOfStructs);
The structures are accessed via a offset like so:
(ptr + i)->field;
The structures have 2 fields that are character pointers as follows:
typedef struct
{
char *first;
char *second;
}STUCTNAME;
These fields are allocated memory as follows:
(ptr + i)->first = (char *)malloc(strlen(buffer));
This appears to work but when I try to free the pointers within the structures I get a segmentation fault 11 when I do this:
free((prt + i)->first);
Help?
Notes:
buffer is a character array. Offsetting a pointer by a integer should increment the pointer by the size of what it is pointing to times the integer correct?
Here is a link to my full source code. I have not written some of the functions and I am not using the freeAllpointers and printAll yet.
https://drive.google.com/file/d/0B6UPDg-HHAHfdjhUSU95aEVBb0U/edit?usp=sharing
OH! Thanks everyone! Have a happy Thanksgiving! =D (If you're into that kinda stuff)
In case, you don't initialize all those members in that piece of code, you're not showing us:
Allocate the struct storage (STRUCTNAME*) with calloc(), so that all allocated memory, namely firstand second are zero at the beginning. Passing NULL to free() will result in a no-op. Passing any wild (garbage) pointer to free() may cause a segmentation fault.
To detect a double-free, set ptr[i].first = NULL; after free(ptr[i].first); as a defensive measure for testing.
Notes: buffer is a character array. Offsetting a pointer by a integer
should increment the pointer by the size of what it is pointing to
times the integer correct?
Yes, except for void* on those compilers, which don't define sizeof(void), which is defined to have undefined behavior, to a value > 0: What is the size of void?
Edit:
void makeReviews(FILE *input, REVIEW *rPtr, int numReviews) <-- This does NOT return the new value of rPtr. In main(), it will remain NULL.
Do something like this:
REVIEW* makeReviews(FILE *input, int numReviews);
//...
int main(){
//...
rPtr = makeReviews(input,numReviews);
//...
}
or
void makeReviews(FILE** input,REVIEW** rPtrPtr,int numReviews){
REVIEW* rPtr = *rPtrPtr;
//...
*rPtrPtr = rPtr;
}
//...
int main(){
//...
makeReviews(input,&rPtr,numReviews);
//...
}
fgets(cNumReviews, sizeof(cNumReviews), input); <-- Perhaps, you could use something like fscanf().

Are "malloc(sizeof(struct a *))" and "malloc(sizeof(struct a))" the same?

This question is a continuation of Malloc call crashing, but works elsewhere
I tried the following program and I found it working (i.e. not crashing - and this was mentioned in the above mentioned link too). I May be lucky to have it working but I'm looking for a reasonable explanation from the SO experts on why this is working?!
Here are some basic understanding on allocation of memory using malloc() w.r.t structures and pointers
malloc(sizeof(struct a) * n) allocates n number of type struct a elements. And, this memory location can be stored and accessed using a pointer-to-type-"struct a". Basically a struct a *.
malloc(sizeof(struct a *) * n) allocates n number of type struct a * elements. Each element can then point to elements of type struct a. Basically malloc(sizeof(struct a *) * n) allocates an array(n-elements)-of-pointers-to-type-"struct a". And, the allocated memory location can be stored and accessed using a pointer-to-(pointer-to-"struct a"). Basically a struct a **.
So when we create an array(n-elements)-of-pointers-to-type-"struct a", is it
valid to assign that to struct a * instead of struct a ** ?
valid to access/de-reference the allocated array(n-elements)-of-pointers-to-type-"struct a" using pointer-to-"struct a" ?
data * array = NULL;
if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) {
printf("unable to allocate memory \n");
return -1;
}
The code snippet is as follows:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
typedef struct {
int value1;
int value2;
}data;
int n = 1000;
int i;
int val=0;
data * array = NULL;
if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) {
printf("unable to allocate memory \n");
return -1;
}
printf("allocation successful\n");
for (i=0 ; i<n ; i++) {
array[i].value1 = val++;
array[i].value2 = val++;
}
for (i=0 ; i<n ; i++) {
printf("%3d %3d %3d\n", i, array[i].value1, array[i].value2);
}
free(array);
printf("freeing successful\n");
return 0;
}
EDIT:
OK say if I do the following by mistake
data * array = NULL;
if ((array = (data *)malloc(sizeof(data *) * n)) == NULL) {
Is there a way to capture (during compile-time using any GCC flags) these kind of unintended programming typo's which could work at times and might blow out anytime! I compiled this using -Wall and found no warnings!
There seems to be a fundamental misunderstanding.
malloc(sizeof(struct a) * n) allocates n number of type struct a elements.
No, that's just what one usually does use it as after such a call. malloc(size) allocates a memory region of size bytes. What you do with that region is entirely up to you. The only thing that matters is that you don't overstep the limits of the allocated memory. Assuming 4 byte float and int and 8 byte double, after a successful malloc(100*sizeof(float));, you can use the first 120 of the 400 bytes as an array of 15 doubles, the next 120 as an array of 30 floats, then place an array of 20 chars right behind that and fill up the remaining 140 bytes with 35 ints if you wish. That's perfectly harmless defined behaviour.
malloc returns a void*, which can be implicitly cast to a pointer of any type, so
some_type **array = malloc(100 * sizeof(data *)); // intentionally unrelated types
is perfectly fine, it might just not be the amount of memory you wanted. In this case it very likely is, because pointers tend to have the same size regardless of what they're pointing to.
More likely to give you the wrong amount of memory is
data *array = malloc(n * sizeof(data*));
as you had it. If you use the allocated piece of memory as an array of n elements of type data, there are three possibilities
sizeof(data) < sizeof(data*). Then your only problem is that you're wasting some space.
sizeof(data) == sizeof(data*). Everything's fine, no space wasted, as if you had no typo at all.
sizeof(data) > sizeof(data*). Then you'll access memory you shouldn't have accessed when touching later array elements, which is undefined behaviour. Depending on various things, that could consistently work as if your code was correct, immediately crash with a segfault or anything in between (technically it could behave in a manner that cannot meaningfully be placed between those two, but that would be unusual).
If you intentionally do that, knowing point 1. or 2. applies, it's bad practice, but not an error. If you do it unintentionally, it is an error regardless of which point applies, harmless but hard to find while 1. or 2. applies, harmful but normally easier to detect in case of 3.
In your examples. data was 4 resp. 8 bytes (probably), which on a 64-bit system puts them into 1. resp. 2. with high probability, on a 32-bit system into 2 resp. 3.
The recommended way to avoid such errors is to
type *pointer = malloc(num_elems * sizeof(*pointer));
No.
sizeof(struct a*) is the size of a pointer.
sizeof(struct a) is the size of the entire struct.
This array = (data *)malloc(sizeof(data *) * n) allocates a sizeof(data*) (pointer) to struct data, if you want to do that, you need a your array to be a data** array.
In your case you want your pointer to point to sizeof(data), a structure in memory, not to another pointer. That would require a data** (pointer to pointer).
is it valid to assign that to struct a * instead of struct a ** ?
Well, technically speaking, it is valid to assign like that, but it is wrong (UB) to dereference such pointer. You don't want to do this.
valid to access/de-reference the allocated array(n-elements)-of-pointers-to-type-"struct a" using pointer-to-"struct a" ?
No, undefined behavior.

Resources