I am trying to make a linked list stack, and I followed a tutorial online, however I get this warning, and the author does not.
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
typedef struct stack {
int data;
struct stack *next;
} stack;
stack *top;
void Initialize(stack *s){
s=malloc(sizeof(stack));
s->data=NULL;
s->next=NULL;
top=s;
return;
}
During debugging I get a segmentation fault, if I don't use malloc in the initialize function.
MINGW-W64 compiler.
The warning is due to the fact the the NULL macro is defined (by most modern compilers) as ((void *)0), as it is intended to be used only for pointers. Assigning this value to the data member of your structure causes the warning.
To remove this warning, use s->data=0; in place of s->data=NULL;. The author of the tutorial is either using an older compiler or has disabled this particular warning.
Also, the pointer (s) passed to your Initialize function will be a copy of whatever variable you use as an argument when you call that function and, as such, its value is not updated in the calling code. You haven't specified how you intend to use that function, but here is a (perhaps) better implementation:
stack* Initialize(void) { // Don't need an argument - just return the 'answer'
stack* made = malloc(sizeof(stack));
if (made) { // Don't attempt the initialization if "malloc" failed!
made->data = 0;
made->next = NULL;
}
return made;
}
And then, when you call that function, you can assign its returned value to your 'global' top pointer:
//...
top = Initialize();
// You should check that 'top' is not NULL before continuing!
In C the macro NULL is defined like
( void * )0
that is the type of the expression is a null pointer of the type void *.
Thus in this statement
s->data=NULL;
a pointer is assigned to an object of the type int and the compiler issues a message saying that you are doing something wrong.
The function Initialize as it is written does not make a sense. Apart of all for example this statement
s=malloc(sizeof(stack));
does not change the original pointer top used as the function argument.
In fact the function is redundant.
Nevertheless if to write such a function then it can look either like
stack * Initialize( void )
{
return NULL;
}
and called like
stack *top = Initialize();
or like
void Initialize( stack **top )
{
*top = NULL;
}
Or for a new created node it can be declared and defined like
void Initialize( stack *s, int data, stack *next )
{
s->data = data;
s->next = next;
}
Related
In our code base, I encountered some C code that I am not able to understand why it works.
Pretty sure implements some pattern found on the internet. Ideally this code should emulate some object-oriented pattern from C++, and it is used to create queues.
Here is (part of) the code for the declaration (.h) of the queue module:
struct Queue_t
{
uint8_t Queue[MAX_QUEUE_SIZE];
uint32_t Head;
uint32_t Tail;
uint16_t Counter;
Queue_return_t (*Push)(struct Queue_t * Queue, uint8_t * NewElement, uint16_t ElementSize);
Queue_return_t (*Pop)(struct Queue_t * Queue, Queue_Element_t *RetElement);
Queue_return_t (*Flush)(struct Queue_t * Queue);
};
extern const struct QueueClass {
struct Queue_t (*new)( void );
} Queue_t;
struct Queue_t new( void );
Here is (part of) the code for the implementation (.c) of the queue module:
struct Queue_t new( void )
{
struct Queue_t NewQueue;
[...]
NewQueue.Push = &QueueManager_Push;
NewQueue.Pop = &QueueManager_Pop;
NewQueue.Flush = &QueueManager_Flush;
return NewQueue;
}
const struct QueueClass Queue_t={.new=&new};
then the usage in the code is the following:
struct Queue_t Output_Queue;
Output_Queue = Queue_t.new();
[...]
RetQueue = Output_Queue.Pop(&Output_Queue,Output_Queue_elem);
Now, we switched to a more straightforward queue implementation.
Still I am not able to grasp what is going on in this code.
As stated in the title, my problem is in the "new" function, where a struct Queue_t is declared in a local scope and then returned.
As further information, in the project that used this "queue" module there was no dynamic memory allocation, hence no heap, free or malloc.
Everything worked really smooth, I would expect the code to crash as soon as the stack for the referenced object is freed and the pointer to the structure is accessed.
Also, the compiler used was IAR and is not complaining (this code was used on a uC).
Maybe the const qualifier is involved?
Any hint on what is going on?
It is perfectly legal to return a value declared inside a function. The problem only arises if you return a pointer to a value declared inside a function, and then try to access it.
The new() function you show is equivalent to:
int foo(void) {
int a = 123;
return a;
}
There is no problem here, you're returning a value which is copied to the destination when doing:
int x;
x = foo(); // copy happens here
Using x after this is not accessing the (now vanished) stack of foo, since x is defined outside foo and was copied when the function returned.
Doing this with a struct is no different, a struct is still treated as a single value, the only real difference is in the generated machine code, since copying a structure takes more effort (you need to copy each field).
The problem, again, only arises when you return a pointer to a locally defined variable and try using it outside:
int *foo(void) {
int a = 123;
return &a; // never do this!
}
int main(void) {
int *x;
x = foo();
return *x; // OUCH!
}
Now dereferencing x (both for reading and for writing) means trying to access the (now vanished) stack of foo, and this is of course a problem.
I have an data structure that stores a generic void * for each node which gets casted to the correct type at the appropriate time. In the cleanup function for this object, I would then like to provide a callback so that this generic object can too be "cleaned up."
struct foo {
void *data;
// ...
};
void foo_cleanup(struct foo *foo, void (*data_cleanup)(void *data)) {
data_cleanup(foo->data);
// ...
}
// ...
void bar_cleanup(void *data) {
struct bar *bar = (struct bar *)data;
// ...
}
This works fine, however I would prefer if the signature of bar_cleanup referred to bar directly, rather than void *:
void bar_cleanup(struct bar *bar)
Of course, replacing that code as is creates "parameter type mismatch" warnings. Is there any way to achieve directly what I am trying to do, if not a similar method of achieving the same cleanup task?
What you are doing now is the correct way to deal with it. Your desire to use pointers to cleanup functions with a specific type runs foul of the (strict) rules in C11 (and C99, and probably C90 though I've not formally checked C90).
[§6.3] Conversions
§6.3.2.3 Pointers
¶8 A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.
Your existing code is:
struct foo {
void *data;
// ...
};
void foo_cleanup(struct foo *foo, void (*data_cleanup)(void *data)) {
data_cleanup(foo->data);
// ...
}
void bar_cleanup(void *data) {
struct bar *bar = (struct bar *)data;
// ...
}
This code is clean and obeys the rules. The pointer to the bar cleanup function has the signature void (*)(void *) which matches the pointer used by foo_cleanup(). The cast in bar_cleanup() is optional but explicit. Even if you omit the cast notation, that conversion will occur as C automatically converts from void * to struct bar *.
If you try to use the cleanup function:
void bar_cleanup(struct bar *bar);
you would have to make a call equivalent to:
struct foo foo37;
…code initializing foo37…
foo_cleanup(&foo37, (void (*)(void *))bar_cleanup);
This coerces the type of the function to a different pointer type. Unless the code inside foo_cleanup() knows somehow (how?) that the pointer needs to use function with the signature void (*)(struct bar *) and changes it before calling the cleanup function, it runs afoul of the rule in §6.3.2.3.
foo_cleanup(struct foo *foo, void (*data_cleanup)(void *data))
{
(*data_cleanup)(foo->data); // Undefined behaviour
if (data->…)
(*(void (*)(struct bar *))data_cleanup)(foo->data); // OK, but…
…
}
The unconditional call is wrong because the types of the real function pointer and the one claimed by the parameter type are different. The conditional call is clean because it casts the pointer back to its real type before calling the function. (This is C; the conversion from void * to struct bar * is automatic and valid.) . However, having to know what to convert the pointer-to-function to in the foo_cleanup() function defeats the purpose of using a pointer-to-function in the first place. It also isn't clear how foo_cleanup() does determine which cast is correct, and if you add a new type, you have to change the code again to support the new type.
All of this means that a solution using void bar_cleanup(struct bar *bar) is not really acceptable.
If you follow the strict rules laid down by the standard and still want to call void bar_cleanup(struct bar *), you have to write gruesome, non-maintainable, inflexible code.
If you want absolutely reliable code, you will follow these rules and keep your existing code (void bar_cleanup(void *data)). It has the beneficial side-effect of avoiding painful casts — function pointer casts are not pretty — and leaves the foo_cleanup() function unchanged regardless of how many different pointer types are stored in the data member of struct foo as long as the calling code knows which is the correct type (and if the calling code doesn't know, it's a case of "Abandon Hope All Ye Who Enter Here" anyway).
In practice, how serious a problem is this? Actually, you'll probably get away with it at the moment. But it is invoking undefined behaviour and compilers are ever eager to identify and exploit undefined behaviour to 'optimize' the code they generate. You can do as you want without the cast in foo_cleanup(), but you are
taking risks which can be simply and painlessly avoided by keeping your current code.
Note that this applies to comparator functions passed to qsort() or bsearch() in the standard library. Those functions should be written to take two const void * parameters and return an int. Doing otherwise runs foul of §6.3.2.3.
There are examples in otherwise respected C books that do not keep to these strict rules.
typedef void (*CLEANUP_FUNC)(void *);
void foo_cleanup(struct foo *foo, CLEANUP_FUNC *data_cleanup) {
data_cleanup(foo->data);
// ...
}
void bar_cleanup(struct bar *data) {
// ...
}
foo_cleanup(foo, (CLEANUP_FUNC *)bar_cleanup);
The following is a full example featuring generic stack Stack and some elements of type Foo.
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
// ---
typedef void (STACK_DEALLOCATOR)(void *);
typedef struct Stack {
STACK_DEALLOCATOR *element_deallocator;
size_t num_elements;
size_t num_allocated;
void **elements;
} Stack;
Stack *Stack_New(STACK_DEALLOCATOR *element_deallocator) {
Stack *this = malloc(sizeof(Stack));
if (this == NULL)
goto ERROR;
this->element_deallocator = element_deallocator;
this->num_elements = 0;
this->num_allocated = 4;
this->elements = malloc(sizeof(void *) * this->num_allocated);
if (this->elements == NULL)
goto ERROR2;
return this;
ERROR2: free(this);
ERROR: return NULL;
}
int Stack_Push(Stack *this, void *element) {
if (this->num_elements == this->num_allocated) {
// ...
}
this->elements[ this->num_elements++ ] = element;
return 1;
}
void Stack_Destroy(Stack *this) {
void **element = this->elements;
for (size_t i=this->num_elements; i--; ) {
this->element_deallocator(*(element++));
}
free(this->elements);
free(this);
}
// ---
typedef struct Foo {
int data;
// ....
} Foo;
Foo *Foo_New(int data) {
Foo *this = malloc(sizeof(Foo));
if (this == NULL)
return NULL;
this->data = data;
return this;
}
void Foo_Destroy(Foo *this) {
free(this);
}
// ---
int main(void) {
Stack *stack = Stack_New((STACK_DEALLOCATOR *)Foo_Destroy);
if (stack == NULL) {
perror("Stack_New");
goto ERROR;
}
Foo *foo = Foo_New(123);
if (foo == NULL) {
perror("Foo_New");
goto ERROR2;
}
if (!Stack_Push(stack, foo)) {
perror("Stack_Push");
goto ERROR3;
}
Stack_Destroy(stack);
return 0;
ERROR3: Foo_Destroy(foo);
ERROR2: Stack_Destroy(stack);
ERROR: return 1;
}
In the below code snippet I'm getting a gcc compiler warning: "passing argument 1 of initArr from incompatible pointer type initArr(&stack,2);"
and a note: "expected 'struct Arr *' but argument is of type 'struct Arr**'"
which makes perfect sense to me.
As suggested by many a SO post, dropping the ampersand from the call to initArr(&stack, 2) however, results in another warning: "'stack' is used unitialized in this function: init(stack, 2);" and an immediate segfault error when ran.
What am I doing incorrectly?
I also tried using struct Arr in the malloc sizeof call and as expected, no change.
#include<stdio.h>
#include <stdlib.h>
#define TYPE int
struct Arr {
TYPE * data; // Pointer to the data array.
int size; // Number of elements in the array.
int capacity; // Capacity of the array.
};
void initArr(struct Arr * da, int capacity) {
da->data = malloc(sizeof(TYPE) * capacity);
da->size = 0;
da->capacity = capacity;
}
int main() {
struct Arr *stack;
initArr(&stack, 2);
return 0;
}
As haccks answer says,
you need to initialize your pointer, so it points to a real location
pass the pointer (rather than the address of the pointer variable)
int main()
{
struct Arr realArray; // allocate memory for the Arr (on the CPU's stack)
struct Arr *stack; // pointer variable (undefined)
stack = &realArray; // make variable "stack" point to realArray
initArr(stack, 2); // pass the pointer to realArray
}
stack is a pointer and it must be pointing to some valid memory location. Since stack is passed to the function and isn't initialized, you are getting a warning. In the function you are trying to access some random memory location which can cause the program crash or any erroneous behavior of the program, aka undefined behavior.
Change this:
struct Arr *stack;
To this:
struct Arr stack;
First look at the declaration of your initArr function:
void initArr(struct Arr * da, int capacity)
Your first argument is of type 'pointer to a struct'
Now look at your invocation of this function:
struct Arr *stack;
initArr(&stack, 2);
We see that stack is of type 'pointer to a struct', and in the function you are passing the address of stack (.i.e. the type is a pointer to a pointer to a struct). Which is what the gcc error is about, the note actually gives more information about the type that the function expects and the type that you are providing
There are two ways to fix this
leave the declaration of initArr as it is, and then change the function
invocation from initArr(&stack, 2) to initArr(stack, 2). In this case you will need to make sure that you have allocated memory for the structure prior to passing it to the function;
int main()
{
struct Arr* da = NULL;
da = malloc(sizeof(struct Arr));
initArr(da, 2);
}
or equivalently,
int main
{
struct Arr stack;
initArr(&stack, 2);
}
I would probably go for one of the above solutions.
Modify the declaration of initArr to initArray(struct Arr** da, int capacity). You will still need to make sure memory is allocated as before. However, if you change initArr to:
void initArr(struct Arr** da, int capacity)
{
*da = malloc(sizeof(struct Arr));
(*da)->data = malloc(sizeof(TYPE) * capacity);
(*da)->size = 0;
(*da)->capacity = capacity;
}
In this case I am changing the semantics of your initArr function so that I am initializing the structure all in one place. The code in your main function would remain unchanged.
N.B. For clarity, error checking has been omitted in the above code snippets, please don't do this in real code. Always check the return value from malloc to ensure that memory has been allocated.
I am trying to create a struct object (stack) which consists of:
typedef struct node {
int val;
struct node * next;
}node_t;
typedef struct {
node_t * top;
int max_size;
int used_size;
} Stack;
However, when I try to initialize the object and allocate it some memory space using the function:
Stack * newStack(int max_size) {
Stack * S = malloc(sizeof(Stack));
S->top = NULL;
S->max_size = max_size;
S->used_size = 0;
return S;
}
Stack * S = newStack(256); //error here
I get the error referred to above -
function call is not allowed in constant expression
I have never come across this type of error before, and I don't know how to tackle it. Any help is appreciated.
In C language objects with static storage duration can only be initialized with constant expressions.
You are initializing a global variable S, which is an object with static storage duration. Your expression newStack(256) is not a constant expression. As the compiler told you already, you are not allowed to call functions in constant expressions. Hence the error. That's all there is to it.
If you want to have a global variable S, then the only way to "initialize" it with newStack(256) is to do it inside some function at program startup. E.g.
Stack * S;
int main()
{
S = newStack(256);
...
}
When in C, Make sure that your call to a function is done inside a function. For instance:-
#include <stdlib.h>
int return_something()
{
return 100;
}
int something = return_something();
This would obviously through an error, to resolve the issue, call int_something() from inside some other function frame
is there difference between with or without * for function pointer in C?
my function pointer declaration like this
typedef void (*DListVisitNode) (Node*, void*);
void DListTraverse( NodeList* , DListVisitNode , void*);
i have code like these
void print_index( Node* node, void* ctx)
{
printf("index:%d\n", node->index);
}
void* print_content( Node* node, void* ctx)
{
printf("content:%s\n", node->content);
}
void DListTraverse(NodeList* nodelist, DListVisitNode visit_func, void* ctx)
{
Node* cur_node = nodelist->headnode;
while( cur_node != NULL)
{
visit_func( cur_node, ctx );
cur_node = cur_node->nextnode;
}
}
DListTraverse( nodelist, print_content, NULL );
DListTraverse( nodelist, print_index, NULL );
both of DListTraverse works, but the one with * throws warning like this
warning: passing argument 2 of ‘DListTraverse’ from incompatible pointer type
i would simply delete the * afterward, but what's the difference between them?
print_content is defined as returning a void* i.e. a generic raw pointer.
print_index is defined as returning void i.e. without any results.
These are different signatures. Only print_index matches DListVisitNode.
My coding style is to define signature thru typedef like
typedef void signature_t (int);
Notice that no pointer is involved above. This names the signature of functions with one int argument and no results.
then, when needing pointers to such functions of above signature, use signature_t*
What is true is that the name of a function is like the name of an array; the language implicitly convert these to pointers. So DListTraverse(nodelist, print_content, NULL) is understood like DListTraverse(nodelist, &print_content, NULL)
You should enable all warnings on your compiler; with gcc that means giving -Wall -Wextra as program arguments to the compiler.
You've declared print_content as returning a void * (a pointer), which means it doesn't match DListVisitNode. However, as the function doesn't actually return anything (no return statement), you should be gatting another warning about that.
You may be confused about the difference between the following to typedefs:
typedef void (*DListVisitNode) (Node*, void*);
typedef void * (*DListVisitNode) (Node*, void*);
Or equivalently, between the following two types:
void (*) (Node *, void *)
void * (*) (Node *, void *)
The former is a pointer to a function returning void, the latter is a pointer to a function returning void *. Each of your print functions is an example of one such function.
Naturally, function pointers of different types are incompatible and not implicitly convertible, as surely this would make no sense: You can't just pretend that a function actually has a completely different signature and expect to be able to call it in any meaningful way. It would be like pretending that a bicycle is a car and then trying to refuel it at a gas station.
typedef void (*DListVisitNode) (Node*, void*);
Defines a pointer to an function as an type which takes two parameters Node * and void * and returns a void.
Once you use the above statement, DListVisitNode can be used as an type, the exact type is as mentioned above.
void* print_content( Node* node, void* ctx)
returns a void * and not a void.
C is a strongly typed language, the c standard mandates that any type violations must be reported by the compiler, hence there is a type mismatch and the compiler reports it to you. Basically, if your function doesn't return anything use the return type as void or if you intend to return a particular type then use that specific type as an return type.