How can I allocate a pointer to a struct in C? - c

#include <stdlib.h>
struct foo{
int a;
};
int main(int argc, char * * argv){
struct foo * bar = malloc(sizeof(struct foo));
free(bar);
return EXIT_SUCCESS;
}
Wouldn't this cause undefined behavior according to the standard? If so, what should I do instead to adhere to the standard?
https://stackoverflow.com/a/1241314/13959281

If the question is what will happen if the malloc fails and bar will be assigned NULL, then the answer is: nothing will happen when free is called. free function checks if the pointer passed is NULL. If the pointer is NULL no action is taken. So there is no UB here.
As a general remark: it is safer (or at least less error-prone) if instead of types the actual objects are used:
struct foo * bar = malloc(sizeof(*bar));
#EDIT#
OPs comment clarifies the question. The size of pointer in the implementation does not matter as C standard guarantees that any pointer to object type (not function pointer) can be converted to void * and void * can be converted to any type of pointer. How it is actually done is left to the implementation. So it is 100% safe as it is guaranteed by the C standard.

Related

Can the memory allocated by the malloc function be freed after the type of the pointer pointing to the memory is transformed?

Recently, I am trying to understand how to efficiently free the memory space allocated by the malloc function in the C language. And I have got some ideas about this, but I am not sure whether they are right or wrong. So, I come here to ask for some suggestions.
For example:
Fisrt, I define a Structure, i.e. demo. And use demo to define a structure pointer, i.e. demo *demo_pointer = NULL. Then, using malloc function to allocate a piece of memory space to this pointer, i.e. demo_pointer = (demo *)malloc(sizeof(demo)). Normally, to free this memory space, I need fisrt to do "free(demo_pointer)", next to do "demo_pointer = NULL".
But, if I use "free((char *)demo_pointer)", can I free the allocated memory?
If this can work, I think I could define a function to do this:
void Free(void **p)
{
free(*p);
*p = NULL;
return;
}
Thus, to free the allocated memory space, I only need to do "Free(&demo_pointer)". Does it work?
Thanks for your kind suggestions!
If the goal is to ensure that the pointer variable is set to NULL after the call to free(), a simpler solution might be to simply define a macro.
#define myFree( p ) do { free(p); p = NULL; } while(0)
/* code */
char *foo = malloc( 80 );
/* omitting test for success */
/* code */
myFree( foo ); // 'foo' will now be set to NULL
Yes is the answer to the question in title, and to the question whether passing the address of demo_pointer to your Free function would free the memory or not.
But, if I use "free((char *)demo_pointer)"
Not fatal but free's signature accepts void *.
I would recommend you to read more about memory allocation and de-allocation functions. Especially the functions prototype as what they accept as arguments/parameters and what do they return.
Normally, to free this memory space, I need fisrt to do
"free(demo_pointer)", next to do "demo_pointer = NULL".
demo_pointer = NULL is not mandatory. The demo_pointer is already freed by free. This is just a cosmetic way of indicating that the memory pointed by demo_pointer was freed.
This helps in cases where the demo_pointer is getting accessed later in the program, there demo_pointer can be checked:
if (!demo_pointer) {
/* do something */
} else {
/* do something else */
}
If your concern is efficiently freeing the memory, then free just does that. Just make sure that the previously allocated memory/address is not mangled up.
And if you want all the freed up addresses to point to NULL value by default then the Free function in your question is just fine. You could get rid of the return.
The question asks:
But, if I use free((char *)demo_pointer), can I free the allocated memory?
The short answer is: No
Explanation:
When it comes to malloc and free the important thing is the value of the void pointer returned by malloc. When you later call free you need to pass a void pointer with the exact same value.
Now the C standard specifies that if a void pointer is converted to any other pointer type and back to void pointer, the resulting value will be equal to the value of the original void pointer.
So code like
T* var = malloc(...); // Implicit conversion: void pointer to T pointer
free(var); // Implicit conversion: T pointer to void pointer
is fine. First a void pointer is (implicit) converted to a T pointer and then the T pointer is (implicit) converted back to a void pointer which is used as argument for free. That is exactly the conversion steps that the standard guarantee to give identical values.
However the code
demo* demo_pointer = (demo *)malloc(sizeof(demo));
free((char *)demo_pointer);
is doing these pointer conversions:
void pointer --> demo pointer // explict cast (btw: not needed in C)
demo pointer --> char pointer // explicit cast
char pointer --> void pointer // implicit conversion
The C standard does not guarantee that this sequence of pointer conversion will result in the final void pointer being equal to the initial void pointer. Consequently, the final void pointer can't be used when calling free
It will probably work on any real world system but the standard has no such guarantee.
Regarding your function:
The prototype is
void Free(void **p)
so the function expects a pointer to pointer to void
When calling it like
Free(&demo_pointer)
the argument is a pointer to pointer to demo
These are incompatible types so the function is incorrect.
Compiling this code
struct demo *demo_pointer = malloc(sizeof *demo_pointer);
Free(&demo_pointer);
with "gcc -Wall -Wextra" also gives warning like:
main.cpp: In function 'main':
main.cpp:40:10: warning: passing argument 1 of 'Free' from incompatible pointer type [-Wincompatible-pointer-types]
40 | Free(&d);
| ^~
| |
| struct demo **
main.cpp:16:18: note: expected 'void **' but argument is of type 'struct demo **'
16 | void Free(void **p)
| ~~~~~~~^
that tells you that it's the wrong thing to do.

what does it mean to have a void* member of a struct in c?

I don't understand what kind of property the mystery member is below:
typedef struct _myobject
{
long number;
void *mystery;
} t_myobject;
What kind of member is this void member? How much memory does that take up? Where can I get more information about what that accomplishes (for instance, why would one use a void member?)
EDIT-- updated title to say void*
A void* variable is a "generic" pointer to an address in memory.
The field mystery itself consumes sizeof(void*) bytes in memory, which is typically either 4 or 8, depending on your system (on the size of your virtual memory address space, to be more accurate). However, it may point to some other object which consumes a different amount of memory.
A few usage examples:
int var;
char arr[10];
t_myobject obj;
obj.mystery = &var;
obj.mystery = arr;
obj.mystery = malloc(100);
Your struct declaration says void *, and your question says void. A void pointer member is a pointer to any kind of data, which is cast to the correct pointer type according to conditions known at run-time.
A void member is an "incomplete type" error.
Variable of type void * can hold address of any symbol. Assignment to this variable can be done directly but while dereferencing it needs to be type cast to the actual type. This is required to inform the compiler about how much memory bytes needs to be accessed while dereferencing. Data type is the one which tells the size of a variable.
int a = 10;
char b = 'c';
void *c = NULL;
c = &a;
printf("int is %d\n", *((int*)c));
c = &b;
printf("char is %c\n", *(char*)c));
In above example void pointer variable c stores address of int variable a at first. So while dereferencing void pointer c, its typecasted to int *. This informs the compiler to access 4 byte (size of int) to get the value. And then in second printf its typecasted to char *, this is to inform the compiler to access one byte (size of char) to get the value.
Wrong question header. The member is 'void *', not 'void'.
A pointer to anything, rather than nothing.

Void pointers pretending to be void double pointers

I've been doing some thinking. I haven't found anything directly answering this question, but I think I know the answer; I just want some input from some more experienced persons.
Knowns:
A void pointer points to just a memory address. It includes no type information.
An int pointer points to a memory address containing an int. It will read whatever is in the memory address pointed to as an integer, regardless of what was stuffed into the address originally.
Question:
If a void double pointer void ** foo were to point to a dynamically allocated array of void pointers
void ** foo = malloc(sizeof(void *) * NUM_ELEMENTS);
is it true, as I am supposing, that because of the unique nature of void pointers actually lacking any sort of type information that instead of void ** foo an equivalent statement would be
void * bar = malloc(sizeof(void *) * NUM_ELEMENTS);
and that when I use indirection to access by assigning a specific type, such as with
(It was pointed out that I can't dereference void pointers. For clarity to the purpose of the question the next line is changed to be appropriate to that information)
int ** fubar = bar;
that I would get an appropriate pointer from the single void pointer which is just acting like a double pointer?
Or is this all just in my head?
It is permissible to assign the result of malloc to a void * object and then later assign it to an int ** object. This is because the return value of malloc has type void * anyway, and it is guaranteed to be suitable for assignment a pointer to any type of object with a fundamental alignment requirement.
However, this code:
#define NUM_ELEMENTS 1000
void *bar = malloc(sizeof(void *) * NUM_ELEMENTS);
int **fubar = bar;
*fubar = 0;
is not guaranteed by the C standard to work; it may have undefined behavior. The reason for this is not obvious. The C standard does not require different types of pointers to have the same size. A C implementation may set the size of an int * to one million bytes and the size of a void * to four bytes. In this case, the space allocated for 1000 void * would not be enough to hold one int *, so the assignment to *fubar has undefined behavior. Generally, one would implement C in such a way only to prove a point. However, similar errors are possible on a smaller scale: There are C implementations in which pointers of different types have different sizes.
A pointer to an object type may be converted to a pointer to another object type provided the pointer has alignment suitable for the destination type. If it does, then converting it back yields a pointer with the original value. Thus, you may convert pointers to void * to pointers to void and back, and you may convert pointers to void * to pointers to int * and back, provided the alignments are suitable (which they will be if the pointers were returned by malloc and you are not using custom objects with extended alignments).
In general, you cannot write using a pointer to an object type and then read the same bytes using a pointer to a different object type. This violates aliasing rules. An exception is that if one of the pointers is to a character type. Also, many C implementations do support such aliasing, but it may require setting command-line options to enable such support.
This prohibition on aliasing includes reinterpreting pointers. Consider this code:
int a;
int *b = &a;
void **c = (void **) &b;
void *d = *c;
int *e = (int *) d;
In the fourth line, c points to the bytes that b occupies but *c tries to interpret those bytes as a void *. This is not guaranteed to work, so the value that d gets is not necessarily a pointer to a, even when it is converted to int * as in the last line.
Under the C Standard, the behavior of the code you gave is undefined because you allocated an array of void pointers and then tried to use it as an array of int pointers. There is nothing in the Standard that requires these two kinds of pointer to have the same size or alignment. Now if you had said
void * bar = malloc(sizeof(int*) * NUM_ELEMENTS);
int ** fubar = bar;
Then all would be fine.
Now on the vast majority of machines, an int* and a void* will actually have the same size and alignment. So your code ought to work fine in practice.
Additionally, these two are not equivalent:
void ** foo = malloc(sizeof(void *) * NUM_ELEMENTS);
void * bar = malloc(sizeof(void *) * NUM_ELEMENTS);
This is because foo can be dereferenced at any element to get a void pointer, while bar cannot. For example, this program is correct and prints 00000000 on my 32-bit machine:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
void **a = calloc(10, sizeof(void*));
printf("%p\n", a[0]);
return 0;
}
One other point is that you seem to be thinking that type information is explicit in the pointer at the machine level. This is not true (at least for the vast majority of implementations). The type of C pointers is normally represented only while the program is being compiled. By the time compilation is done, explicit type information is normally lost except in debugging symbol tables, which are not runnable code. (There are some minor exceptions to this. And for C++ the situation is very different.)

Incomplete type compilation error with malloc memory allocation

static char st[][8192];
void foo ( int tab_size){
st = (char**) malloc ((tab_size+1)*sizeof(char)*8192);
}
I receive the compilation error in "malloc" line that st has incomplete type. What is wrong? Thanks.
Since you don't specify the size of the inner dimension for st, the compiler doesn't know how big it needs to be; hence the type is incomplete, and you never complete it before the malloc call.
Since it looks like your intent is to allocate st dynamically, go with Oli's advice and declare it as a pointer to an 8192-element array of char:
static char (*st)[8192];
and rewrite your malloc statement as
st = malloc(sizeof *st * (tab_size+1));
sizeof *st == sizeof (char [8192]) == 8192. This form is a bit cleaner and easier to read. Note also that in C, you don't have to cast the result of malloc (unless you're using a pre-C89 implementation, in which case, I'm sorry), and the practice is discouraged.
This will allocate enough space to hold tab_size + 1 arrays of 8192 characters each.
It is only within the context of a function parameter declaration that T a[] declares a as a pointer to T.
Your definition for st is indeed not a complete type.
Try this instead:
static char (*st)[8192];
void foo (int tab_size){
st = malloc ((tab_size+1)*sizeof(*st));
}
You are confusing two completely different types: an array vs pointer to an array.
static char st[][8192];
declares st to be of type array. It is not a modifiable lvalue and can't be assigned to.
If your intent was to allocate space for an array of integers and assign it to a pointer use the pointer declaration suggested by Oli Charlesworth.
Note that your declaration of st won't allocate space though. if you try something like this, you would get an error..
printf("0x%x\n", st);
Compiler is treating it like a declaration and expects to see the actual definition elsewhere.
Its not a definition because you haven't given the value for the array's first dimension.

C difference between *[] and **

This might be a bit of a basic question, but what is the difference between writing char * [] and char **? For example, in main,I can have a char * argv[]. Alternatively I can use char ** argv. I assume there's got to be some kind of difference between the two notations.
Under the circumstances, there's no difference at all. If you try to use an array type as a function parameter, the compiler will "adjust" that to a pointer type instead (i.e., T a[x] as a function parameter means exactly the same thing as: T *a).
Under the right circumstances (i.e., not as a function parameter), there can be a difference between using array and pointer notation though. One common one is in an extern declaration. For example, let's assume we have one file that contains something like:
char a[20];
and we want to make that visible in another file. This will work:
extern char a[];
but this will not:
extern char *a;
If we make it an array of pointers instead:
char *a[20];
...the same remains true -- declaring an extern array works fine, but declaring an extern pointer does not:
extern char *a[]; // works
extern char **a; // doesn't work
Depends on context.
As a function parameter, they mean the same thing (to the compiler), but writing it char *argv[] might help make it obvious to programmers that the char** being passed points to the first element of an array of char*.
As a variable declaration, they mean different things. One is a pointer to a pointer, the other is an array of pointers, and the array is of unspecified size. So you can do:
char * foo[] = {0, 0, 0};
And get an array of 3 null pointers. Three char*s is a completely different thing from a pointer to a char*.
You can use cdecl.org to convert them to English:
char *argv[] = declare argv as array of pointer to char
char **argv = declare argv as pointer to pointer to char
I think this is a little bit more than syntactic sugar, it also offers a way to express semantic information about the (voluntary) contract implied by each type of declaration.
With char*[] you are saying that this is intended to be used as an array.
With char**, you are saying that you CAN use this as an array but that's not the way it's intended to be used.
As it was mentioned in the other answers, char*[] declares an array of pointers to char, char** declares a pointer to a pointer to char (which can be used as array).
One difference is that the array is constant, whereas the pointer is not.
Example:
int main()
{
char** ppc = NULL;
char* apc[] = {NULL};
ppc++;
apc++; /* this won't compile*/
return 0;
}
This really depends on the context of where the declarations occur.
Outside of a function parameter definition, the declaration
T a[];
declares a as an unknown-sized array of T; the array type is incomplete, so unless a is defined elsewhere (either in this translation unit or another translation unit that gets linked) then no storage is set aside for it (and you will probably get an "undefined reference" error if you attempt to link, although I think gcc's default behavior is to define the array with 1 element) . It cannot be used as an operand to the sizeof operator. It can be used as an operand of the & operator.
For example:
/**
* module1.c
*/
extern char *a[]; /* non-defining declaration of a */
void foo()
{
size_t i = 0;
for (i = 0; a[i] != NULL; i++)
printf("a[%lu] = %s\n", (unsigned long) i, a[i++]);
}
module1.c uses a non-defining declaration of a to introduce the name so that it can be used in the function foo, but since no size is specified, no storage is set aside for it in this translation unit. Most importantly, the expression a is not a pointer type; it is an incomplete array type. It will be converted to a pointer type in the call to printf by the usual rules.
/**
* module2.c
*/
char *a[] = {"foo", "bar", "bletch", "blurga", NULL}; /* defining declaration of a */
int main(void)
{
void foo();
foo();
return 0;
}
module2.c contains a defining declaration for a (the size of the array is computed from the number of elements in the initializer), which causes storage to be allocated for the array.
Style note: please don't ever write code like this.
In the context of a function parameter declaration, T a[] is synonymous with T *a; in both cases, a is a pointer type. This is only true in the context of a function parameter declaration.
As Paul said in the comment above, it's syntactic sugar. Both char* and char[] are the same data type. In memory, they will both contain the address of a char.
The array/index notation is equivalent to the pointer notation, both in declaration and in access, but sometimes much more intuitive. If you are creating an array of char pointers, you may want to write it one way or another to clarify your intention.
Edit: didn't consider the case Jerry mentioned in the other answer. Take a look at that.
char *ptr[2]={"good","bad"}; //Array of ptr to char
char **str; //Refer ptr to ptr to char
int i;
//str = &ptr[0]; //work
str = ptr;
for(i=0;i<2;i++) printf("%s %s\n",ptr[i],str[i]);
Its o/p same. Using that we can easily understand.

Resources