Problems with array of pointers to struct - c

After defining the type student (which is a struct made of two arrays of characters and an int), I've created an array of pointers to student, which I need in order to modify its content inside of a series of functions.
int main(void)
{
student* students[NUMBER_OF_STUDENTS];
strcpy(students[0]->name, "test");
strcpy(students[0]->surname, "test");
students[0]->grade = 18;
return EXIT_SUCCESS;
}
My problem is that this simple piece of code returns -1 as exit status after running. Why is that?

The pointer students[0] is uninitialized. Dereferencing it results in undefined behavior.
Initialize it with the address of a valid object before attempting to access it.
student test;
students[0] = &test;
strcpy(students[0]->name, "test");
strcpy(students[0]->surname, "test");
students[0]->grade = 18;

Because it is UB. You have only pointer without the actual structs allocated.
students[x] = malloc(sizeof(*students[0]));
or statically
student s;
students[x] = &s;
or
students[x] = &(student){.name = "test", .surname ="test", .grade = 18};

The pointers are pointing to nowhere since you have not allocated any memory for them to point to.
int main(void)
{
student* students = (student*)malloc(sizeof(student)*[NUMBER_OF_STUDENTS]); \\malloc dynamically allocate heap memory during runtime
strcpy(students[0]->name, "test");
strcpy(students[0]->surname, "test");
students[0]->grade = 18;
return EXIT_SUCCESS;
}
*Note Edit by marko -- Strictly the pointers are pointing to whatever was last in the stack location or register holding it - it may be nothing, or something you actually care about. The joys of UB

Related

Idiom for aliasing structs

I understand that C is (mostly) call and assign "by value", and that struct assignment a = b creates a copy of b.
This leads to some verbosity when iterating through an array whose members are struct, and accessing member fields (example below). Is there an idiom for aliasing structs in a loop?
#include <stdio.h>
#define N_FOOS 2
struct Foo {
char *bar;
char *baz;
};
int main() {
struct Foo foos[N_FOOS] = {
{"foo", "bar"},
{"baz", "qux"},
};
for (int i = 0; i < N_FOOS; ++i) {
printf("foos[%d].bar = %s\n", i, foos[i].bar);
printf("foos[%d].baz = %s\n", i, foos[i].baz);
}
}
In a higher-level language I would have created an alias within for to point to foos[i] and avoid repeated indexing.
Would the idiomatic way be to create a pointer that references foos[i]?
int main() {
struct Foo *foo;
struct Foo foos[N_FOOS] = {
{"foo", "bar"},
{"baz", "qux"},
};
for (int i = 0; i < N_FOOS; ++i) {
foo = &foos[i];
printf("foos[%d].bar = %s\n", i, foos[i].bar);
printf("foos[%d].baz = %s\n", i, foos[i].baz);
printf("foo->bar = %s\n", foo->bar);
printf("foo->baz = %s\n", foo->baz);
}
}
The downside is having to do manual deallocation, but I guess that's just an inescapable part of the language.
EDIT: fixed code due to #dbush's feedback
What you have will work fine. It can be especially useful if you have a structure several layers deep to abbreviate what you're referring to and make your code more clear.
The one problem you have is a memory leak. You dynamically assign memory to foo, but then you overwrite the address of that allocated memory with the address of another variable:
foo = &foos[i];
Now the allocated memory is lost.
Because you're using the pointer to point to an existing variable, you don't need dynamic allocation at all. Get rid of malloc and free.
Your program is incorrect. Here's how to fix it: Remove the malloc on the RHS, replace it with NULL, and remove the free line.
You're just moving the pointer, so there's no need to do manual allocation, and if you free the last value, that's a bug because you're freeing something that wasn't malloced.

Releasing pointer memory aswell as pointer itself

A "Deeltal" keeps track of how many dividers an integer has (count) and keeps them in an array (dividers).
Examples:
value = 8 -> count = 3 and dividers = {1,2,4}
value = 10, count = 3, dividers = {1,2,5}
Hope everything is clear, take a look at the following code:
typedef struct{
int value;
int count;
int* dividers;
} Deeltal;
void free_dividers(Deeltal *g){ /*Deletes the int* dividers of a given Deeltal*/
free (g - > dividers);
}
/* the following two functions have the same purpose: deleting the content of a
given amount of "Deeltal" AND deleting the pointer to it aswell*/
void free_amountOfdeeltal(Deeltal *d, int amount){
int i;
for (i = 0; i < amount; i++){
free_dividers(&d[i]);
}
free(d);
}
void free_amountOfdeeltalVersion2(Deeltal **g, int amount){
int i;
for(i = 0; i < amount; i++){
free_dividers(&(*g)[i]);
}
free(*g);
}
If my main looked something like this
int main(void){
/*EDIT 3/11/2017: forgot to allocate memory for *d and initializing g.
Thanks for pointing this out*/
Deeltal g = 0;
g.value = 6; g.count = 3; g.dividers = {1,2,3};
Deeltal *d = malloc(sizeof(Deeltal));
d->value = 6; d->count = 3; d->dividers = {1,2,3};
free_amountOfdeeltal(&g);
free_amountOfdeeltalVersion2(&d);
}
What is the difference between free_amountOfdeeltal and free_amountOfdeeltalVersion2?
Both should do the same thing: releasing the memory of a Deeltal and also deleting the pointer pointing to that memory.
On a sidenote:
How do you delete the memory as well as the pointer?
Not withstanding calling this function with invalid data as pointed out by others .. I'll attempt to answer the question I think you are asking.
On a sidenote: How do you delete the memory as well as the pointer?
You can't really "delete the pointer" in this context as a pointer is simply a variable that is assigned an address. You delete memory that was allocated to you by passing free a pointer to the memory. Note that free does not modify the value of the pointer at all. (It can't because the pointer is passed by value.) After the call to free the pointer still points to the same memory address.
If what you mean is "how can I assign a meaningful value to the pointer to identify that its memory has already been deleted," then you can use the second form of your function:
void free_amountOfdeeltalVersion2(Deeltal **g, int amount);
and set *g to NULL before returning. You can then use this information than the pointer is NULL to identify the memory has already been deleted.
You didn't allocate any memory for d so your pointer doesn't point to any structure. Therefor, you can't access its properties or free its memory because you didn't reserve it in the first place. There's no way this code could come remotely close to compiling.
First of all you should be allocating memory for a "Deeltal" structure like this:
Deeltal *d = malloc(sizeof(Deeltal));
I recommend you go back and relearn how pointers work, as you're doing some really weird stuff there.

struct pointer and void pointer confusion while doing malloc

typedef struct data
{
int *data_array;
int *thread_number;
}array;
....
int main(int argc, char *argv[]){
...
int size = atoi(argv[1]);
array *array_ptr;
array_ptr->data_array = malloc((size+2)*sizeof(int));//failing line
....
}
because of the failing line it gives me seg. fault
how must solve it
In your code,
array *array_ptr;
array_ptr->data_array = malloc((size+2)*sizeof(int));//failing line
array_ptr itself is used uninitialized. If you try to dereference an unitialized pointer, you'll invoke undefined behavior. Segmentation fault is one of the many effects of UB.
You should allocate memory to array_ptr first, like
array *array_ptr = NULL;
array_ptr = malloc(sizeof *array_ptr);
if (array_ptr) //check for malloc success
{
array_ptr->data_array = malloc((size+2)*sizeof(int));
.....
}
else
{
printf("failure\n");
exit(-1);
}
When you define a local variable like this
array *array_ptr;
array_ptr pointer is given a place in memory, but it does not point to a valid array struct in memory: the value of uninitialized variable contains some random "garbage" value. Therefore, dereferencing it in any way, including
array_ptr->data_array = malloc ...
is undefined behavior.
You can fix it by allocating some memory to the array pointed to by array_ptr, like this:
array *array_ptr = malloc(sizeof(array));
Segmentation fault is expected as you have not created any memory for array_ptr and you are trying to reference it which eventually will try to access the data_array(for which there is no memory yet ) So , kernel will signal the process to terminated and hence you will get segmentation fault here .
int size = atoi(argv[1]);
array *array_ptr;
array_ptr->data_array = malloc((size+2)*sizeof(int));//failing line
However , to fix this , you shold first create memory for array_ptr .
array *array_ptr = (array * )malloc(sizeof(array));//type casting is necessary as malloc returns pointer to void .
After this you can check the pointer and assign memory to its data members
if(array_ptr )
{
array_ptr->data_array = malloc((size+2)*sizeof(int));//type cast here also
}
int size = atoi(argv[1]);
array *array_ptr;
array_ptr->data_array = (*int) malloc(sizeof(int)*(size+2));
Works?
-- Edit --
I get the number from argv and transform in int.
Create the structute.
I create the memory whith the size than a int plus (arg + 2), and associate this in the struct, only

variable may be used before being set

I am getting "variable may be used before being set" when I create a pointer to a structure example *e. If I use a variable instead example e, I am not getting the error. Is this because I haven't allocated memory for the pointer?
typedef struct example {
int a;
}example;
void test (){
example *e;
e->a=1;
printf_all("val %d",e->a);
}
e is NOT pointing to anything. You are using an uninitialized pointer. You "set" through an invalid pointer, and then trying to access it.
Your pointer should point to an example instance. For example:
example exampleInstance;
example * examplePointer = &exampleInstance;
The pointer has an indeterminate value. As result the program has undefined behaviour.
You should allocate memory for an object of type example where you are going to write data. For example
example *e = malloc( sizeof( *e ) );
e->a = 1;
In this case you should free the memory when it will not be needed any more.
Or
example obj;
example *e = &obj;
e->a = 1;

Changing values in elements of an array of structs

I am working on an assignment and ran into challenging problem. As far as I'm concerned and from what I've learnt the code that follows should be correct however it does not work. Basically what I am trying to is copy a string value into the variable member of a structure the is part of an array passed into a method as a pointer. What am I missing?
typedef struct
{
char * name; //variable in struct I am trying to access
} Struct;
void foo(Struct * arr) //array of Structs passed into function as a pointer
{
int i = 0;
while(i++ < 2)
{
arr[i].name = malloc(sizeof(char *)); //assigning memory to variable in each Struct
arr[i].name = strdup("name"); //copying "name" to variable in each Struct
printf("C - %s\n", arr[i].name); //printing out name variable in each Struct
}
}
main()
{
Struct * arr; //defining pointer
arr = calloc(2, sizeof(Struct)); //allocating memory so pointer can hold 2 Structs
foo(arr); //calling function foo passing pointer into function
return 0;
}
This code compiles and runs however it does not do what it is designed to do. Forgive me if it is something trivial. I am new to the language C
Two issues:
while(i++ < 2) This line changes the value of i as soon as it checks it, so your loop body will not be the same as it was checked.
arr[i].name = strdup("name"); overwrites the value of the .name pointer, causing a memory leak of the memory you malloc()'ed earlier.
Extending on 2 pointed out correctly already,
arr[i].name = strdup("name");
Even if you use following instead of above,
strcpy(array[i].name, "name");
you haven't allocated enough bytes to store the string i.e. this is wrong
arr[i].name = malloc(sizeof(char *));
// even if pointer is 8 byte here, concept isn't right
Should be something like
arr[i].name = malloc(strlen("name")+1);
// or MAX_SIZE where it is greater than the possible "name".
Or better yet, remove the malloc at all, strdup takes care of allocation itself
This is not answering your question directly, but addresses an issue to big to put into a comment...
Additional issue: You probably did not intend to allocate only a (char *) worth of memory to a variable intended to hold at least "name". Change;
arr[i].name = malloc(sizeof(char *));
to:
arr[i].name = malloc(sizeof(char)*strlen("name")+1); //+1 for '\0'
or better yet, use char *name="name";, then:
arr[i].name = malloc(sizeof(char)*strlen(name)+1);
Even more general (and better):
char *name;
name = malloc(strlen(someInputString)+1);
//do stuff with name...
free(name);
Now, you can allocate name to any length needed based on the length of someInputString.
[EDIT]
Etienz, I wanted to address one more thing, alluded to by #H2CO3 above, but not really explained, that I think might be useful to you:
Regarding your desire to have room for two structs, because you typedef'd your struct, you can simply do something like this: (but I am going to change the name you used from Struct to NAME :) The whole point being that when a struct is created as an array, you do not need to use calloc or malloc to create space for them, it is done as shown below...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char *name;
}NAME;
//use new variable type NAME to create global variables:
NAME n[2], *pN; //2 copies AND pointer created here
//prototype func
int func(NAME *a);
int main()
{
pN = &n[0]; //pointer initialized here
func(pN); //pointer used here (no malloc or calloc)
printf("name1 is %s\nname 2 is %s", pN[0].name, pN[1].name);
return 0;
}
int func(NAME *a)
{
char namme1[]="andrew";
char namme2[]="billebong";
//You DO have to allocate the members though
a[0].name = malloc(strlen(namme1)+1);
a[1].name = malloc(strlen(namme2)+1);
strcpy(a[0].name, namme1);
strcpy(a[1].name, namme2);
return 0;
}

Resources