Compiler warnings and notes but dropping & does not work - c

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.

Related

Why does this pointer declaration work with malloc()?

I am new to C and have a question about a specific pointer declaration:
Here is a program i wrote:
#include <stdlib.h>
struct n {
int x;
int y;
};
int main()
{
struct n **p = malloc(sizeof(struct n));
return 0;
}
The declaration here is not be correct but why not?
Here is my thought process:
The man page of malloc specifies that it returns a pointer:
The malloc() and calloc() functions return a pointer to the
allocated memory, which is suitably aligned for any built-in
type.
The type of p is struct n** aka a pointer to another pointer.
But shouldn't this declaration work in theory because:
malloc returns type struct n* (a pointer)
and p points to the pointer that malloc returns
so it is essentially a pointer to another pointer
so the type of p is fulfilled
Sorry if this is a dumb question but i am genuinely confused about why this does not work. Thanks for any help in advance.
The return type of malloc is not struct n *, regardless of how it is called. The return type of malloc is void *.
Initializing a struct n ** object with a value of type void * implicitly converts it to struct n **. This implicit conversion is allowed, because the rules for initialization follow the rules for assignment in C 2018 6.5.16.1 1, which state one of the allowed assignments is:
… the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;…
and p points to the pointer that malloc returns
No, the value p is initialized to the value that malloc returns. Then p points to the memory malloc allocated.
It is a mistake for this code to allocate enough space for a struct n (using malloc(sizeof(struct n))) but assign the address of that space to the struct n ** that is p. To point to a struct n, use struct n *p = malloc(sizeof (struct n)); or, preferably, struct n *p = malloc(sizeof *p);.
To pointer to a pointer to a struct n, first create some pointer to a struct n, as with the above struct n *p = malloc(sizeof *p);. Then a pointer to that pointer would be struct n **pp = &p;.
If you wanted to allocate space for those pointers-to-pointers, you could do it with struct n **pp = malloc(sizeof *pp);, after which you could fill in the pointer to the struct n with *pp = malloc(sizeof **pp);. However, you should not add this additional layer of allocation without good reason.
Note that the form MyPointer = malloc(sizeof *MyPointer); is often preferred to MyPointer = malloc(sizeof (SomeType)); because the former automatically uses the type that MyPointer points to. The latter is prone to errors, such as somebody misintepreting the type of MyPointer and not setting SomeType correctly or somebody later changing the declaration of MyPointer but omitting to make the corresponding change to SomeType in the malloc call.
This doesn't really work. In this example, malloc is returning a void *, which points to a newly allocated place in the heap that is large enough to hold a struct n.
Note that malloc() returns type void *, which is basically a pointer to any potential type, malloc() DOES NOT return type struct n * (a pointer to your declared struct type). void * has the special property of being able to be cast to any other type of pointer, and back again.
All together this means that your code doesn't actually work, since the first dereference of your struct n** would be a struct n, not a struct n*. If you tried to dereference twice, you would most likely get an invalid memory reference and crash.
The reason that your code can compile and run without crashing is because:
The compiler automatically casts void * to struct n **
You never attempt to actually dereference your pointer, which means you never attempt an invalid memory reference.
Simplify the problem and understanding may come:
int main()
{
struct n data;
struct n *pData = &data; // skipped in your version
struct n **ppData = &pData;
// struct n **ppData = &data; // Will not compile
// struct n **ppData = (struct n **)&data; // Casting but wrong!
return 0;
}
Because malloc() returns a void ptr, you are free to store the pointer into anything that is a pointer datatype. On your head if you put it into the wrong datatype...

assignment to 'int' from 'void *' makes integer from pointer without a cast

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;
}

C - Structure's pointer

I'm having trouble understanding pointers in general I think.
I can't seem to follow the logic of this code:
typedef struct StackRecord
{
int Capacity;
int TopOfStack;
int* Array;
}*Stack;
In the following structure, *Stack was declared to receive addresses of StackRecord structure type via simply stating Stack due to typedef
BUT code below the return another receiver of addresss of StackRecord structure type. Why isn't it returning the address? But rather return same type of pointer to itself?
Stack CreateStack(int MaxElements)
{
Stack S;
if (MaxElements < MinStackSize)
{
printf("Error : Stack size is too small");
return 0;
}
S = (Stack)malloc(sizeof(struct StackRecord));
if (S == NULL)
{
printf("FatalError : Out of Space!!!");
return 0;
}
S->Array = (int*)malloc(sizeof(char)* MaxElements);
if (S->Array == NULL)
{
printf("FatalError : Out of Space!!!");
return 0;
}
S->Capacity = MaxElements;
MakeEmpty(S);
return S;
}
Getting rid of the typedef may make things a little clearer, believe it or not:
struct StackRecord
{
int Capacity;
int TopOfStack;
int* Array;
};
/**
* Return a pointer to a new, dynamically allocated instance
* of struct StackRecord
*/
struct StackRecord *CreateStack(int MaxElements)
{
struct StackRecord *S;
if (MaxElements < MinStackSize)
{
printf("Error : Stack size is too small");
return 0;
}
S = malloc(sizeof *S); // no need for cast, sizeof *S is same as sizeof (struct StackRecord)
if (S == NULL)
{
printf("FatalError : Out of Space!!!");
return 0;
}
/**
* Allocate the memory for the Array member of
* the new stack record instance.
*/
S->Array = malloc( sizeof *S->Array * MaxElements );
if (S->Array == NULL)
{
printf("FatalError : Out of Space!!!");
return 0;
}
S->Capacity = MaxElements;
MakeEmpty(S);
return S;
}
In the code you posted, Stack is basically a synonym for struct StackRecord *. The function creates a new instance of struct StackRecord using malloc, initializes the contents of that record, and returns a pointer to that new instance.
A note on the malloc calls - in C, you do not need to cast the result of malloc, and doing so is generally considered bad practice1. Also, the operand to sizeof doesn't have to be a type name - it can be an expression of the type you want to allocate. IOW, given a declaration like
T *p;
both sizeof (T) and sizeof *p do the same thing - the expression *p has type T. So the general form of a malloc call can be written as
T *p = malloc( sizeof *p * N );
or
T *p;
...
p = malloc( sizeof *p * N );
That's simpler to write and easier to maintain than
p = (T *) malloc( sizeof (T) * N );
<rant>
Hiding the pointer-ness of a type behind a typedef is bad juju, especially when the user of that type has to be aware that he or she is dealing with a pointer type. Assigning the result of malloc to S means that S must be a pointer type. Using the -> to access members of S means that S must be a pointer to a struct or union type. Since you have to be aware that S is a pointer, it makes no sense to hide that pointerness behind the typedef. Similarly, if the user has to be aware of the struct-ness of the type, you shouldn't hide that struct-ness behind a typedef either.
Abstraction is a powerful tool, but partial (leaky) abstractions like the original code just make life more confusing for everyone (as you have discovered for yourself).
</rant>
This is not true for C++, because C++ doesn't allow implicit conversions between void * and other pointer types the way C does. But, if you're writing C++, you shouldn't be using malloc anyway.
In the typedef, the type identifier Stack is a pointer to a struct. The function prototype for CreateStack() specifies a return value of type Stack, which is a pointer to a StackRecord struct. S is declared to be of type Stack in the function body, so the function does return a pointer to a StackRecord struct.
In comments on #DavidBowling's answer you express this apparent misconception:
Stack is a pointer to StackRecord which means pointer must contain another address to which it is pointing to.
The typedef declares the identifier Stack to be an alias for the type struct StackRecord *. That would perhaps be clearer if it were rewritten in this wholly equivalent form:
struct StackRecord
{
int Capacity;
int TopOfStack;
int* Array;
};
typedef struct StackRecord *Stack;
No object of type struct StackRecord is declared, only that type itself and type Stack.
When function CreateStack() allocates memory sufficient for a struct StackRecord ...
malloc(sizeof(struct StackRecord));
... it is perfectly reasonable to convert the resulting pointer to type struct StackRecord *. Indeed, type Stack is exactly the same type as struct StackRecord *, so that's precisely what the code in fact does. The converted pointer still points to the same memory, and when that pointer is returned, the return value also points to the same memory.

Adding an array element to an array in a struct

(Proficient at C++, newbie at C) getting a segfault error from the addArray() call in main(). I've checked many posts and several texts, it compiles, but no luck running it. I'm coding it on VS2015 and all the usual handy cues are there with pointers, etc. Cleary something I'm not aware of or a syntax error. This is the distilled code that reproduces the error.
#include<stdio.h>
#include <stdlib.h>
#define TYPE int
struct arrayHolder {
TYPE data[100];
int count;
};
//prototypes.
void initArray(struct arrayHolder * );
void addArray(struct arrayHolder *, TYPE);
int main() {
struct arrayHolder * myStruct = NULL;
initArray(myStruct);
addArray(myStruct, 123);
}
/* Allocate memory for struct arrayHolder */
void initArray(struct arrayHolder * b) {
b = (struct arrayHolder *)malloc(sizeof(struct arrayHolder));
b->count = 0;
}
/* Add an element to data[] */
void addArray(struct arrayHolder * b, TYPE v) {
int count = b->count;
b->data[count] = v;
(b->count)++;
}
As #def1 observed, you are passing pointers by value. That's not an issue for addArray() -- the problem is with initArray(). That function's parameter is local to the function, so when you assign the malloc()ed pointer to it, the result is not visible in main(). Ultimately, you end up passing a NULL pointer to addArray().
There are at least two possible solutions.
In the code presented, it's not clear to me why the struct arrayholder needs to be dynamically allocated at all. If in main() you declare instead struct arrayholder myStruct; and remove the malloc() call from initArray(), then everything else should work as-is.
Alternatively, if you do need to perform dynamic allocation then either you should return a pointer to the allocated memory from initArray() (in which case that function does not require a parameter) or else you need to pass a double pointer to the function, so that main()'s pointer can be updated thereby.
The only one of those alternatives that should be at all tricky is the double pointer variant, which would look like this:
int main() {
struct arrayHolder * myStruct = NULL;
initArray(&myStruct); /* difference here */
addArray(myStruct, 123);
}
/* Allocate memory for struct arrayHolder */
void initArray(struct arrayHolder ** b) {
/* no cast is required here in C, and many account one poor style: */:
*b = malloc(sizeof(struct arrayHolder));
(*b)->count = 0;
}
void initArray(struct arrayHolder * b)
Here you pass a pointer to a struct arrayHolder to the function. The pointer is passed by value which means it is a copy. You can change the data the pointer is pointing to but when you assign the result of malloc to b you are modifying the copy of the pointer itself, which will not influence the pointer in main.
Possible solution is to use a pointer to a pointer.
void initArray(struct arrayHolder ** b) {
*b = (struct arrayHolder *)malloc(sizeof(struct arrayHolder));
(*b)->count = 0;
}

Double indirection and structures passed into a function

I am curious why this code works:
typedef struct test_struct {
int id;
} test_struct;
void test_func(test_struct ** my_struct)
{
test_struct my_test_struct;
my_test_struct.id=267;
*my_struct = &my_test_struct;
}
int main ()
{
test_struct * main_struct;
test_func(&main_struct);
printf("%d\n",main_struct->id);
}
This works, but pointing to the memory address of a functions local variable is a big no-no, right?
But if i used a structure pointer and malloc, that would be the correct way, right?
void test_func(test_struct ** my_struct)
{
test_struct *my_test_struct;
my_test_struct = malloc(sizeof(test_struct));
my_test_struct->id=267;
*my_struct = my_test_struct;
}
int main ()
{
test_struct * main_struct;
test_func(&main_struct);
printf("%d\n",main_struct->id);
}
The first version working is just dumb luck. Try randomly calling something else after test_func returns but before you call printf.
The second version is correct. Of course, you didn't free the heap memory, but whether that matters at the end of a program is a matter of debate.
You are right, passing a pointer to something that is allocated on the stack (and therefore goes away when the function returns, is wrong).
Passing a pointer to a heap allocated variable is fine.
"It works" is an illusion. You are returning a pointer to a stack-allocated variable in the first code example.
The pointer will point to garbage -- try dereferencing it...

Resources