Multiple files and structs, differing outputs - c

In this small program, all three files all have different responsibilities.
The goal of the program is to read data from the data.c file into the struct array created in testing.h, which can be then accessed and used in testing.c.
What I am finding is that when I attempt to print outside the local scope and furthermore attempt to print outside the file the output changes.
data.c
void data() {
size_t friends[] = {1,3,4};
userdata[0].friends_ids = friends;
size_t friends2[] = {5,8,9};
userdata[1].friends_ids = friends2;
}
testing.c
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include "testing.h"
#include "data.c"
int main() {
data();
for (int x=0; x<3; x++) {
printf("%d\n", userdata[0].friends_ids[x]);
}
printf("\n");
for (int x=0; x<3; x++) {
printf("%d\n", userdata[1].friends_ids[x]);
}
}
testing.h
struct user {
size_t* friends_ids;
};
struct user userdata[2];
Output:
1
3
4
-1942895168
1680886992
-320301600
It's evident these are garbage values for userdata[1] but I am confused why does userdata[0] print correctly but userdata[1] outputs garbage values?
What I've tried is to allocate memory for the structs but I don't know if it's possible because I keep getting errors saying "initializer element is not constant" despite trying.
struct user *userdata = (struct user *)malloc(2*sizeof(struct user));

As mentioned in the comments, there is the potential for undefined behavior in the posted code, but I did not get that far as the posted code resulted in a run-time error: defreferencing out of bounds pointer on the first call to printf in the main function. (possibly due to UB)
Problems (and suggested fixes) are listed below.
void data() {...
Is not a valid function prototype, and should have thrown a warning. And for your purposes, even:
void data(void) {...
although valid, is not sufficient. Change it to:
void data(struct user User[2]) {...
By the way also the minimum signature for the main function prototype is:
int main(void){...
Once you have made these changes, and given your definition of struct user ,consider the additional edits to data and main: (note, the following suggestions are limited only to illustrate one method of using function arguments to pass/receive data. Program architecture, or other ways to define a struct are left for other discussions.)
void data(struct user User[2]) // pass struct as argument
{
size_t i;
int a[] = {1,2,3};
int b[] = {4,5,6};
for(i=0;i<sizeof(a)/sizeof(a[0]);i++)
{
userdata[0].friends_ids[i] = a[i];
userdata[1].friends_ids[i] = b[i];
}
}
int main(void) {
userdata[0].friends_ids = calloc(3, sizeof(size_t)); // create memory
userdata[1].friends_ids = calloc(3, sizeof(size_t));
data(&userdata[2] ); //populate struct pointers (pass pointer to struct)
// values returned from call to data() are refreshed and ready to use.
for (int x=0; x<3; x++) { // use struct data
printf("%d\n", userdata[0].friends_ids[x]);
}
printf("\n");
for (int x=0; x<3; x++) {
printf("%d\n", userdata[1].friends_ids[x]);
}
free(userdata[0].friends_ids); // free memory
free(userdata[1].friends_ids);
return 0;
}

Related

Dynamic array in structs

I have a problem using dynamic memory in C.
I am creating a struct whose data is a number and a pointer to another struct (in short, an array of struct). The goal is for the parent struct to store an array of another struct using dynamic memory.
The problem I have is to access the cells of the created array, because I don't know if it's due to syntax issues (I'm new to C), or that I'm creating the array wrong, I can't modify the information contained in each cell of the contained array inside the parent struct. I can only modify by default the first cell.
This is my code, any idea or suggestion will be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char string[64];
void* date;
void* colour;
} DataState;
typedef struct {
int number;
DataState* array;
} Book;
Book* makeBook (int number){
int a=5;
void* auxiliary=&a;
Book* book_A=(Book*)(malloc(sizeof(Book)));
book_A->number=number;
book_A->array=(DataState*)(malloc(number*sizeof(DataState))); //creating array of structs inside main struct.
//And what I want to do is something like this, modify the information contained in cells of the array of structs of the main struct.
book_A->array[3]->date=auxiliary;
return book_A;
}
From already thank you very much.
Here:
book_A->array[3]->date=auxiliary;
you assign a value of auxiliary to the 3rd element of an array, but auxiliary is defined as
void* auxiliary=&a;
while a is an automatic variable in your function.
Automatic variables disappear at the return from the function, hence the pointer assigned to book_A->array[3]->date becomes invalid as soon as the return is executed.
If you want the data saved in a to remain valid after makeBook returns, then you must allocate it in more persistent storage than automatic. You've essentially done this:
int* foo()
{
int a = 5;
// WRONG, cannot return the address of a local variable
return &a;
}
int main(void)
{
int* a_addr = foo();
// WRONG, invokes undefined behavior
printf("a = %d\n", *a_addr);
}
If you want a to persist outside of foo, a possible option is:
int* foo()
{
int* a = malloc(sizeof *a);
// always check the return value of malloc
if (a != NULL)
{
*a = 5;
}
// this is ok. `a` is still in automatic storage, but this _returns_ its
// value, which is a pointer to data _not_ in automatic storage.
return a;
}
int main(void)
{
int* a_addr = foo();
// still must check here, malloc in `foo` could have failed. Probably
// better to design an architecture where you only check validity once
if (a_addr != NULL)
{
printf("a = %d\n", *a_addr); // prints a = 5
// don't forget to `free(a_addr)` when you're done with it, or you can
// let the OS clean up the memory when the process exits.
}
else
{
// handle error how you want
fprintf(stderr, "Out of mem!\n");
}
return 0;
}

Passing an array from a method in file 1 to a method in file 2 without using a extra parameter in a method

I am getting all Zeroes in global_array_of_file2.Idea is to get the updated values from file1.c
========================file1.c===========================
#include <stdio.h>
#include <string.h>
int global_array_of_file1[10];
void func1(int a1,int b)
{
int array1_of_func1[10] = {0};
int a;
array1_of_func1[5] = 23;
array1_of_func1[6] = 34;
memcpy(global_array_of_file1,array1_of_func1,10*sizeof(int));
for (a = 0; a < 9; a++)
{
printf("from func_1 : global_array = %d \n " , global_array_of_file1[a]);
}
}
void init_pointer(int *tmp)
{
tmp = global_array_of_file1;
}
~
==========================file2.c======================
#include<stdio.h>
#include "file1.h"
int global_array_of_file2[10] = {0};
int main()
{
int i;
init_pointer(global_array_of_file2);
func1(3,4);
for(i = 0; i < 9 ; i++)
{
printf("global_array_of_file2 = %d \n" , global_array_of_file2[i]);
}
return 0;
}
========================file1.h===========================
void init_pointer(int *tmp);
void func1(int a,int b);
There are two issues here:
First issue is:
the code for init_pointer does nothing:
void init_pointer(int *tmp)
{
tmp = global_array_of_file1;
}
as tmp variable is a copy of the input variable (called by value), it does nothing.
To have it work correctly it should be something like this:
void init_pointer(int **tmp)
{
*tmp = global_array_of_file1;
}
However, as the global_array_of_file2 is declared as array, it is actually a static pointer which cannot be changed, so you cannot modify its value using statement like **tmp= global_array_of_file1.
Therefor to make it work, you should call memcpy within the init pointer method:
like this:
void init_pointer(int *tmp)
{
memcpy( tmp, global_array_of_file1, 10 * sizeof(int) );
}
The second issue, is that the code at main, first call the init_pointer (which does nothing), then it calls 'func1' which initialize the array. the order shall be the opposite. first call func1 to set the array with the appropriate values, then call the init_array method to copy this information to global array 2.
so instead of
init_pointer(global_array_of_file2);
func1(3,4);
it shall be
func1(3,4);
init_pointer(global_array_of_file2);
This is all if you want to have a copy of the global_array_file1 at file2.
If you want, you can have the same array shared between files, to do so:
at file1.h declare the array as extern:
extern int global_array_of_file1[10];
Then you can simply use it at file2.c which include file1.h
Ok I think this can be fixed easily by doing the below :
declare extern int global_array_of_file1[10] in file1.c
define int global_array_of_file1[10] = {0}; in file2.c
I then dont even need to initialize the pointer from file2.c ( no need to call init_pointer) and extra RAM too will be saved :) !
The memcpy is wrong. You just copy 10 bytes.
An int is usually 4 Bytes long (32 bit), thus you only copy parts of the array, namely the first ten bytes, thus you copy just the ints with index 0,1,2 and half of 4.
You need to copy 10 * sizeof(int)

Passing a struct to a function

So I am trying to pass my struct to a function and I am also trying to assign my variable to the struct, which does not seem to work. I don't know what's wrong with it either.
This is how my code looks:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ACE 1;
#define CardSize 52
#define colors 4
struct MyCards {
int *cards;
char *color[4];
};
void count(struct MyCards record);
int main() {
struct MyCards record;
count(record);
system("pause");
return 0;
}
void count(struct MyCards record) {
int i, j, f;
// I actually want to put this variable and the values into the struct, how do i do it?
char *color[4] = { "Diamon", "Heart", "Spade", "Clubs" };
record.cards = malloc(CardSize * sizeof(int));
for (f = 0; f < 4; f++) {
for (i = 0; i < 13; i++) {
record.cards[i] = (i % 13) + 1;
printf("%d of %s\n", record.cards[i], color[f]);
}
}
}
As you might see, the thing I commented out, I also want to put that variable AND the values that I have assign to it, but I dont know how to do that, would love some help there as well.
C uses pass-by-value. record inside count is a different variable to record in main - a copy is made when you call the function.
If you want main to see the changes you either need to return the changed object (in which case you wouldn't pass it in in the first place, in this example), or use pass-by-reference which you implement by passing a pointer to the object.
Returning the object would look like:
struct MyCard count(void)
{
struct myCard record;
// ... do stuff with record ...
return record;
}
Passing by reference would look like:
void count(MyCard *p_record)
{
// ... do stuff with (*p_record)
}
Also you want record.color[f] = color[f]; as the first line of the f loop. And (as discussed last time you posted about this code) you should be using string or char const *, not char *.
You have to pass a pointer to the struct in order to edit it, or you will edit the variable only in the stack of the function, which will be deleted once the function returns. Try passing &record to your function.
Also change your prototype: you have to accept a pointer to the struct.
When you have a pointer, to resolve the struct you have to use the -> operator. Let's do an example:
records->cards[i] = ...

Segfault when trying to index pointer to pointers in function

I'm trying to do something with an array (malloc-ed), namely arr of a custom struct. The array is passed by reference to a function. I get a segfault whenever I tried to index anything other than arr[0] in the function at runtime (e.g (*arr[1])->i = 3;). Why is this happening?
The full source code is:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 100
typedef struct{
int i;
float f;
}foo;
void doSomething(foo ***arr);
int main()
{
foo **arr = (foo**) malloc (SIZE * sizeof(foo*));
int i;
for(i = 0; i < SIZE; i++)
arr[i] = (foo*)malloc(sizeof(foo));
arr[1]->i = 1;
printf("Before %d\n",arr[1]->i );
doSomething(&arr);
printf("After %d\n",arr[1]->i );
return 0;
}
void doSomething(foo ***arr)
{
(*arr[1])->i = 3;
}
Your problem is the line
(*arr[1])->i = 3;
Because the subscripting operator's evaluation precedes the dereferencing's evaluation it is equivalent to the following:
(*(arr[1]))->i = 3;
This is obviously wrong. You need
(*arr)[1]->i = 3;
therefore.
Notes:
do not cast the result of malloc
add #include <stdlib.h> to resolve the warning
adding an extra level of indirection (foo*** pointing to foo**) is unnecessary; just copy by value
(in addition to the upper note) a good old 1D array should actually be sufficient in your case
call free after malloc
The warning you get is because you forgot to #include <stdlib.h>, so malloc is not declared, so the compiler assumes it should return int. This can lead to all kinds of fun problems. (And you should remove those casts.)
The other problem is in this line: (*arr[1])->i = 3;
Postfix operators (like []) bind tighter than prefix operators (like *), so *arr[1] parses as *(arr[1]).
You can write (*arr)[1]->i instead to fix this, but as it turns out, your function never actually modifies *arr, so there's no reason to pass arr (the other arr, the one in main)'s address to it. Just do this:
void doSomething(foo **arr)
{
arr[1]->i = 3;
}
and call it as doSomething(arr).

understanding how to dynamically create an array of structure and access its elements

I need to pass the address of a pointer to a structure to a function, which inturn will dynamically allocate the memory for an array of structures and fill in the values.
Now from my calling method, once i return from the func1, i should be able to iterate through the array of structure and display the value of the structure variables.
Can someone explain how to pass the address of the pointer to the structure, also iterating through the array of structures created dynamically ?
my sample code looks like this:
struct test {
int a;
int b;
};
void func1(int *n,struct test **testobj)
{
n=5;
*testobj = (struct test*) malloc(n*sizeof(struct test));
for(i=0;i<n;i++)
{
(*testobj)[i].a=1;
(*testobj)[i].b=2;
}
}
int main()
{
struct test testobj;int n;
func1(&n,&testobj);
for(i=0;i<n;i++)
{
printf("%d %d",(*testobj)[i].a,*testobj)[i].b);
}
free(testobj);
}
In main() define a pointer to a test structure:
struct test *testPtr;
To take the address of that pointer use the & address-of operator:
&testPtr;
This returns the address of the pointer and has type struct test **
You can then pass this into your function func1, which does the correct allocation (although casting malloc() is generally considered bad practice - Do I cast the result of malloc?). Other than that func1() looks good... the line...
*testobj = malloc(n*sizeof(struct test));
... is correct. *testobj dereferences your double pointer that you got by doing &testPtr, and stores the address of the new memory in your pointer. You are also correct when you dereference your double-pointer using (*testobj)[i] because [] has higher precedence than * you needed to (as you've correctly done) surround the dereference with brackets to make sure that happens before you take the index.
Thus, when func1() returns the pointer testPtr should now point to the array of n test structures you allocated and can be accessed using testPtr[i].a etc.
EDIT: Your for loop should become
for(i=0;i<n;i++)
printf("%d %d", testobj[i].a, testobj[i].b);
Your original for loop should have given you compilation errors? In the original code testobj is not a pointer, therefore dereferencing it should not be possible.
So the summary answer is in main() declare testobj as a pointer and then access the array elements as testobj[n] :)
EDIT: As eric has pointed out, remove n=5; from func1(). I think you meant *n=5 perhaps as some kind of debugging step... You probably mean to use n as the input to the function to say how many objects you want in your structure array. Either initialise n or perhaps re-define func1() to be
void func1(int n,struct test **testobj) // n is no longer a poitner, just a number
create your array of pointers to structures in declaration step itself and simply pass it to the function
struct test *testobj[10];
func1(&n,testobj);
This passes the whole array of pointers to the function
It isn't entirely clear which version you're asking for, but one of these should cover it:
/* allocate some number of tests.
*
* out_n: out parameter with array count
* returns: an array of tests
*/
struct test* allocate_some_tests(int *out_n) {
int n = 5; /* hardcoded, random or otherwise unknown to caller */
*out_n = n
struct test *t = malloc(n * sizeof(*t));
while (n--) {
t[n].a = 1;
t[n].b = 2;
}
return t;
}
/* allocate a specific number of tests.
*
* n: in parameter with desired array count
* returns: an array of tests
*/
struct test* allocate_n_tests(int n) {
struct test *t = malloc(n * sizeof(*t));
while (n--) {
t[n].a = 1;
t[n].b = 2;
}
return t;
}
Note that you can just return the allocated array, you don't need a pointer-to-pointer here.
As for calling them, and iterating over the result:
void print_tests(struct test *t, int n) {
for (; n--; t++)
printf("{%d, %d}\n", t->a, t->b);
}
int main()
{
int count1; /* I don't know how many yet */
struct test *array1 = allocate_some_tests(&count1);
print_tests(array1, count1);
int count2 = 3; /* I choose the number */
struct test *array2 = allocate_n_tests(count2);
print_tests(array2, count2);
}
Your code appears pretty much ok to me.
only edit that should make it fine is--
in place of
struct test testobj;
put the following code
struct test *testobj;
and keep the remaining as it is..!
here's the working version of what's required, here the memory is allocated in the called function just as required
#include <stdlib.h>
#include <stdio.h>
struct tests {
int a;
int b;
};
void func1(int *n,struct tests **testobj)
{
int i;
*n=5;
*testobj = (struct tests*) malloc((*n)*sizeof(struct tests));
for(i=0;i<(*n);i++)
{
(*testobj)[i].a=1;
(*testobj)[i].b=2;
}
}
int main()
{
int i;
struct tests *testobj;int n;
func1(&n,&testobj);
for(i=0;i<(n);i++)
{
printf("%d %d",(testobj)[i].a,testobj[i].b);
}
free(testobj);
}

Resources