Using a struct vs a pointer to a struct - c

I was working on the following as an example to see the differences between passing an object directly and then passing a pointer to it:
#include "stdio.h"
// Car object
typedef struct Car {
char* name;
unsigned int price;
} Car;
void print_car(Car car) {
printf("<Car: %s, Price: $%d>", car.name, car.price);
};
void print_car2(Car *car) {
printf("<Car: %s, Price: $%d>", car->name, car->price);
};
int main(int argc, char* argv[]) {
Car chevy = {chevy.name = "Chevy", chevy.price = 45000};
print_car(chevy);
Car mazda = {chevy.name = "Mazda", chevy.price = 30000};
print_car2(&mazda);
return 1;
}
Other than the first approach being much more readable and easier to understand for me, what are the differences between the two? When would passing a pointer be the only option, and why do both work in the above case?

There are two reasons to use the second approach:
If you want to avoid copying the whole struct. If the struct is big, this can affect performance.
If you want to modify struct that you're passing.

In general (not only for structs) passing a variable to a function will make a copy of this variable so if you want to alter this variable you ll have to return the value of the altered copy but you may want to alter the variable and return something else, in this case you have no other choice of passing a pointer as argument exemple :
first exemple with passing a variable
int useless_func(int nb) /*nb is actually a copy of the variable passed as argument */
{
nb++; /* the copy was incremented, not the real variable */
return nb; /* the new value is returned */
}
int main()
{
int nb = 1;
useless_func(nb); /* here nb is still = 1 cause it wasn't altered by the function */
nb = useless_func(nb); /* here nb is = 2 cause it took the return value of the func */
}
now a second stupid exemple with pointer :
char *useless_func(int *nb) /* nb is now a pointer to the variable */
{
*nb++; /* the derefencement of the pointer (so the variable value) was incremented */
return strdup("This is a useless return"); /* we return some other stupid stuff */
}
int main()
{
int nb = 1;
char *str = useless_func(&nb); /* now nb is = 2 and str is an allocated useless string woohoo */
}

When a function is called, the arguments in a function can be passed by value or passed by reference.
void print_car(Car car)
In here you are directly passing an object to the function, that means it will be copied into the functions stack and destroyed after function call ends. This method should be avoided because copying is expensive and unnecessary. Also if your objects are quite big, this operation will take a lot of time
void print_car2(Car *car) {
In this situation you are passing a pointer to the object which is called pass by reference, that means you are working with the original object and changes you make will directly affect it. It's a lot faster because you are not moving your object, but you should be careful about alter of original data

Related

C - Unable to copy a string in a function

This function is to split string based on \n and see if the row number is selected. If the row number matched, this string should be copied and used by other function:
void selectDeparment(char* departments, int selectedNum, char* selectedDepartment){
char* copyOfDepartments = malloc(strlen(departments)+1);
strcpy(copyOfDepartments,departments);
char* sav1 = NULL;
char* token = strtok_s(copyOfDepartments,"\n",&sav1);
int counter = 0;
while(token != NULL){
if(counter == selectedNum){
selectedDepartment = malloc(strlen(token)+1);
strcpy(selectedDepartment,token);
}
++counter;
token = strtok_s(NULL, "\n", &sav1);
}
}
This function is called in main like:
char* selectedDepartment;
selectDeparment(recordsPtr[0], 1, selectedDepartment);
printf(selectedDepartment);
recordsPtr[0] contains four strings with \n at the end:
aDeparment
anotherDepartment
newDepartment
otherDepartment
In C, we are encouraged to use pointer to get a value from function instead of returning a string from a function. However, the prinft in main function gives random output
I believe there is some confusion in the way you are using pointers here. Let me clarify.
In the main function, the character pointer selectedDepartment holds a certain memory in the computer. But when a function call is made to void selectDeparment(char* departments, int selectedNum, char* selectedDepartment), a new copy of selectedDepartment is created. Henceforth any changes which are made to selectedDepartment are done only at the scope of the called function and does not impact the original pointer in the main function.
Thus one clear way to solve this problem will be to pass a pointer to the character pointer defined in the main function. This will then give the correct/expected results.
Here is the modified version of the function -
void selectDeparment(char* departments, int selectedNum, char** selectedDepartment){
char* copyOfDepartments = malloc(strlen(departments)+1);
strcpy(copyOfDepartments,departments);
char* sav1 = NULL;
char* token = strtok_s(copyOfDepartments,"\n",&sav1);
int counter = 0;
while(token != NULL){
if(counter == selectedNum){
(*selectedDepartment) = malloc(strlen(token)+1);
strcpy(*selectedDepartment,token);
}
++counter;
token = strtok_s(NULL, "\n", &sav1);
}
}
And this is how it is called from the main function -
int main() {
char* recordsPtr[] = {"aDeparment\nanotherDepartment\nnewDepartment\notherDepartment"};
char* selectedDepartment;
selectDeparment(recordsPtr[0], 1, &selectedDepartment);
printf(selectedDepartment);
}
I think you are getting confused with the "A Pointer To What?" you are supposed to return. In your selectDeparment() function, if I understand what is needed, is you simply need to return a pointer to the correct department within recordsPTR. You do not need to allocate or tokenize to do that. You already have the index for the department. So simply change the return-type to char * and return departments[selectedNum];.
For example, you can whittle-down your example to:
#include <stdio.h>
char *selectDeparment (char **departments, int selectedNum){
return departments[selectedNum];
}
int main (void) {
char *selectedDepartment = NULL;
char *recordsPTR[] = { "aDepartment\n",
"anotherDepartment\n",
"newDepartment\n",
"otherDepartment\n" };
selectedDepartment = selectDeparment (recordsPTR, 1);
fputs (selectedDepartment, stdout);
}
Note: the '*' generally goes with the variable name and not the type. Why? Because:
int* a, b, c;
certainly does NOT declare three-pointers to int,
int *a, b, c;
makes clear that you have declared a single-pointer to int and two integers.
Example Use/Output
Running the example above you would have:
$ ./bin/selectedDept
anotherDepartment
You will want to add array bounds protection to ensure the index passed does not attempt to read past the array bounds. That is left to you.
If You Must Use void
If you must use a void type function, then you can pass the Address Of the pointer to the function so the function receives the original address for the pointer in main(). You can then assign the correct department to the original pointer address so the change is visible back in main(). When you pass the Address Of the pointer, it will require one additional level of indirection, e.g.
#include <stdio.h>
void selectDeparment (char **departments, int selectedNum, char **selectedDeparment) {
*selectedDeparment = departments[selectedNum];
}
int main (void) {
char *selectedDepartment = NULL;
char *recordsPTR[] = { "aDepartment\n",
"anotherDepartment\n",
"newDepartment\n",
"otherDepartment\n" };
selectDeparment (recordsPTR, 1, &selectedDepartment);
fputs (selectedDepartment, stdout);
}
(same result, same comment on adding array bounds protection)
Look this over and let me know if I filled in the missing pieces correctly. If not, just drop a comment and I'm happy to help further.

Global pointer set to NULL after calling yylex()

I have a problem of declaring a global scope pointer, in the definition part of my flex file, then i malloc it in the start of my main, but as soon as my program runs into yylex(), the pointer's value is set to NULL.
I need this pointer to a struct (this is struct Modele * model) all along my program, it's basically a pointer to the structure I store all my results from the file in, so I actually cannot do without it, at least not without a pointer to a struct which would work fine in both main() and yylex().
On execution, the program runs into a segfault, trying to write at the adress 0x4 ; running the program under valgrind, and printing the value of model allowed me to understand that the memory was correctly allocated, but as soon as yylex was called, the value of model was NULL (printed (nil)). I don't use any header here, but i tried using one to store all my structures, and the declaration of my global scope variables, but without success.
My question is : what did I do wrong to face such a behavior ? And what is generally the best way not to have this problem ? I'm not sure I ever used global scope pointers, so it could be this, or maybe a flex-lex specific problem .... i'm a bit lost !
Here is a sample of my code :
%{
#include <stdlib.h>
#include <stdio.h>
//some more includes and #defines
typedef struct Doc {
int classe;
uint32_t * words;
int current_index;
int current_size;
} doc;
typedef struct Modele {
int nb_classes;
int nb_docs;
int nb_docs_base;
int nb_docs_test;
int base_or_test;
int voc_size;
int M_test_size;
liste ** M_theta;
row_info * M_calc;
doc * M_test;
} modele;
//some more typedefs
modele * model; // <--- this is the pointer i talk about
//some more functions bodies .....
%}
couple_entiers [0-9]+:[0-9]+
// .......
%%
{couple_entiers} { model->nb_docs ++}
//.....
%%
int main (int argc, char ** argv)
{
// .....
modele * model = malloc(sizeof model); // <---- here is the malloc
model->nb_classes = 0;
model->nb_docs = 0;
model->nb_docs_base = 0;
model->nb_docs_test = 0;
model->voc_size = 0;
model->M_test = malloc (TAB_SIZE * sizeof(doc));
//....
if ((yyin = fopen(argv[1],"r")) == NULL){
printf("Impossible d'ouvrir %s !\n",argv[1]);
exit(0);
}
yylex();
In case that piece of code is not enough to grab the origin of the problem, i'll paste more of it, I just wanted to select the relevant parts.
My question is : what did I do wrong to face such a behavior ?
You never did set the file-scope variable. Your main() function instead declares and initializes a local variable of the same name and type. The local declaration "shadows" the file-scope one within its scope.
To fix it, just change this ...
modele * model = malloc(sizeof model);
... to this:
model = malloc(sizeof model);
If you do not precede the variable name with a type then you are referring to a variable declared elsewhere (in this case, at file scope).

passing and allocating pointer to void* in c

I have used function pointers in c to create a generic struct.
when i call a specific function, one of the parameters is an output parameter. I allocate the memory inside the specific function but it doesn't work. would love some help!
typedef void *PhaseDetails;
typedef Result (*Register)(const char *, PhaseDetails *);
Result Func(const char *file, Register register1){
PhaseDetails firstPhase = NULL;
Result res = register1(file, &firstPhase);
}
int main() {
OlympicSport os = Func("men100mList.txt", (Register) registerMen100m);
return 0;
}
Result registerMen100m(const char *file,
Men100mPhaseDetails *firstPhase) {
firstPhase = malloc(sizeof(*firstPhase));
if (firstPhase == NULL) {
return OG_MEMORY_ALLOCATION_FAILED;
}
*firstPhase = malloc(sizeof(**firstPhase));
(*firstPhase)->phaseName = malloc(sizeof(char)*12);
return OG_SUCCESS;
}
the problem is that the firstPhase returns as NULL
The problem is that you pass a pointer to firstPhase (defined in Func()) into the firstPhase argument of the registerMen100m() function but, as first thing in the function, you overwrite it with the address of a freshly allocated memory block.
After that the value of firstPhase in the Func() function is not, and can not, be changed from within registerMen100m()
Result registerMen100m(const char *file, Men100mPhaseDetails *firstPhase)
{
/* At this point, firstPhase holds the address of the variable
** 'firstPhase' you defined in the 'Func()' function.
*/
firstPhase = malloc(sizeof(*firstPhase));
/* And now it doesnt! So you will never be able to get anything back
*/
if (firstPhase == NULL) {return OG_MEMORY_ALLOCATION_FAILED;}
/* The result of the following malloc is stored in the memory space you
** allocated earlier! If you remove the two lines above you
** should most probably get what you wanted.
*/
*firstPhase = malloc(sizeof(**firstPhase));
(*firstPhase)->phaseName = malloc(sizeof(char)*12);
return OG_SUCCESS;
}
As a general remark using the same name around makes sense only if it means the samething everywhere. Here you have firstPhase with two different meaning in two different functions and this makes difficult to reason about what's happening.
Also, passing functions as arguments is something you very rarely need. Is there any specific reason why you structured the program this way?

Changing pointer address in function

What do I need to change here so that animal contains {3,4}?
void funct(unsigned char *elf)
{
unsigned char fish[2]={3,4};
elf=fish;
}
int main()
{
unsigned char animal[2]={1,2};
funct(animal);
return 0;
}
EDIT: I see memcpy is an option. Is there another way just manipulating pointers?
Is there another way just manipulating pointers?
No, because animal is not a pointer. animal is an array. When you pass it as an argument to the function, it decays to a pointer to its first element, just as if you had said &animal[0].
Even if you use a pointer and take a pointer to it in funct, it still won't work:
void funct(unsigned char** elf)
{
unsigned char fish[2] = { 3, 4 };
*elf = fish; // oh no!
}
int main()
{
unsigned char animal[2] = { 1, 2 };
unsigned char* animal_ptr = animal;
funct(&animal_ptr);
}
After the line marked "oh no!" the fish array ceases to exist; it goes away when funct returns because it is a local variable. You would have to make it static or allocate it dynamically on order for it to still exist after the function returns.
Even so, it's still not the same as what you want because it doesn't ever modify animal; it only modifies where animal_ptr points to.
If you have two arrays and you want to copy the contents of one array into the other, you need to use memcpy (or roll your own memcpy-like function that copies array elements in a loop or in sequence or however).
Since animal decays to a pointer when passed to a function, you can replace:
elf=fish;
with:
elf[0] = fish[0]; // or: *elf++ = fish[0]
elf[1] = fish[1]; // *elf = fish[1]
or, assuming they're the same size:
memcpy (elf, fish, sizeof (fish));
Post question edit:
EDIT: I see memcpy is an option. Is there another way just manipulating pointers?
There is no safe way to do this by manipulating the pointers if you mean changing the value of the pointer itself. If you pass in a pointer to a pointer, you can change it so that it points elsewhere but, if you point it at the fish array, you're going to get into trouble since that goes out of scope when you exit from funct().
You can use the pointer to transfer characters as per my first solution above (elf[n] array access is equivalent to *(elf+n) pointer access).
One option is to assign the elements individually:
void funct(unsigned char *elf){
elf[0] = 3;
elf[1] = 4;
}
Another option is to use memcpy (which requires including string.h):
void funct(unsigned char *elf){
unsigned char fish[2]={3,4};
memcpy(elf, fish, 2);
}
memcpy takes as parameters the destination, the source, and then the number of bytes to copy, in this case 2.
void funct(unsigned char *elf) {
unsigned char fish[2]={3,4}; // stack variable, will dissapear after the function is exited
// elf=fish; this one assigns to the local copy of elf, that will also dissapear when we return
memcpy(elf, fish, sizeof(fish)); // so we have to copy values
// careful though, because sizeof(fish) can be bigger than sizeof(elf)
}
To help deal with maintenance issues, you're probably better off making a function that returns the pointer you want, and then making sure you've really freed any memory from the original array first.
unsigned char * func()
{
unsigned char * fish = malloc( sizeof(unsigned char) * 2 );
fish[0] = 3;
fish[1] = 4;
return fish;
}
int main ( void )
{
unsigned char * animal = malloc( sizeof(unsigned char) * 2 );
animal[0] = 1;
animal[1] = 2;
free( animal );
animal = func();
}
Trying to reassign an array declared using the 'unsigned char animal[2]' syntax is asking for trouble because it's put the entire original array on the stack, and even if the compiler allowed you to do that, you'd end up with a chunk of unusable memory on the stack. I don't design programming languages, but that feels very wrong.

Problem with passing array of pointers to struct among functions in C

The Code that follows segfaults on the call to strncpy and I can't see what I am doing wrong. I need another set of eyes to look it this. Essentially I am trying to alloc memory for a struct that is pointed to by an element in a array of pointers to struct.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_POLICY_NAME_SIZE 64
#define POLICY_FILES_TO_BE_PROCESSED "SPFPolicyFilesReceivedOffline\0"
typedef struct TarPolicyPair
{
int AppearanceTime;
char *IndividualFile;
char *FullPolicyFile;
} PolicyPair;
enum {
bwlist = 0,
fzacts,
atksig,
rules,
MaxNumberFileTypes
};
void SPFCreateIndividualPolicyListing(PolicyPair *IndividualPolicyPairtoCreate )
{
IndividualPolicyPairtoCreate = (PolicyPair *) malloc(sizeof(PolicyPair));
IndividualPolicyPairtoCreate->IndividualFile = (char *)malloc((MAX_POLICY_NAME_SIZE * sizeof(char)));
IndividualPolicyPairtoCreate->FullPolicyFile = (char *)malloc((MAX_POLICY_NAME_SIZE * sizeof(char)));
IndividualPolicyPairtoCreate->AppearanceTime = 0;
memset(IndividualPolicyPairtoCreate->IndividualFile, '\0', (MAX_POLICY_NAME_SIZE * sizeof(char)));
memset(IndividualPolicyPairtoCreate->FullPolicyFile, '\0', (MAX_POLICY_NAME_SIZE * sizeof(char)));
}
void SPFCreateFullPolicyListing(SPFPolicyPair **CurrentPolicyPair, char *PolicyName, char *PolicyRename)
{
int i;
for(i = 0; i < MaxNumberFileTypes; i++)
{
CreateIndividualPolicyListing((CurrentPolicyPair[i]));
// segfaults on this call
strncpy((*CurrentPolicyPair)[i].IndividualFile, POLICY_FILES_TO_BE_PROCESSED, (SPF_POLICY_NAME_SIZE * sizeof(char)));
}
}
int main()
{
SPFPolicyPair *CurrentPolicyPair[MaxNumberFileTypes] = {NULL, NULL, NULL, NULL};
int i;
CreateFullPolicyListing(&CurrentPolicyPair, POLICY_FILES_TO_BE_PROCESSED, POLICY_FILES_TO_BE_PROCESSED);
return 0;
}
Problem is in the prototype of function:
...
void SPFCreateIndividualPolicyListing(PolicyPair *IndividualPolicyPairtoCreate )
{
...
The function gets a NULL pointer value, sets it to a valid location by malloc but doesn't in any way return it to calling function.
It should be
...
void SPFCreateIndividualPolicyListing(PolicyPair **IndividualPolicyPairtoCreate )
{
*IndividualPolicyPairtoCreate = malloc (...);
...
void SPFCreateIndividualPolicyListing(PolicyPair *IndividualPolicyPairtoCreate )
{
IndividualPolicyPairtoCreate = (PolicyPair *) malloc(sizeof(PolicyPair));
That just assigns to the local IndividualPolicyPairtoCreate variable - C is pass by value, not pass by reference. You're leaking memory, and the caller won't see any changes to the struct you're passing in.
Change that function to e.g. return the newly allocated memory, and instead of
CreateIndividualPolicyListing((CurrentPolicyPair[i]));
Do
CurrentPolicyPair[i] = CreateIndividualPolicyListing();
Because I can't read your code with its excessively long variable and function names, I've rewritten the offending function as follows. So, my first suggestion is: use shorter variable names.
void create_policies(SPFPolicyPair **policies, char *name, char *newname) {
int i;
for(i = 0; i < MaxNumberFileTypes; i++) {
create_policy(policies[i]);
strncpy((*policies)[i].IndividualFile, POLICY_FILES_TO_BE_PROCESSED, SPF_POLICY_NAME_SIZE);
}
}
There are multiple problems with this code.
First, as others have pointed out, create_policy(policies[i]) can not change the value of policies[i] because C is purely pass by value. Write it as
polices[i] = create_policy();
and change create_policy to return the address of policy pair it allocates.
Second, (*policies)[i].IndividualFile is wrong. It should be
(*policies[i]).IndividualFile
or even better
policies[i]->IndividualFile.
Third, you don't use name or newname.
Problem (1) and (2) will both lead to segfaults. Problem (3) indicates either that you've been trying to strip this code down to understand the segfault, or that you're not sure exactly what this function should do.
The rest of this post explains the second bug and its fix in more detail.
You have correctly passed in policies as a pointer to the first element of an array of SPFPolicyPair *s. So, very roughly
policies --> [ ptr0 | ptr1 | ptr2 | ... ]
Each ptri value is a SPFPolicyPair *. There are two ways to interpret such a value: (a) the base of an array of SPFPolicyPair objects, or (b) a pointer to a single such object. The language itself doesn't care which interpretation your using, but in your case, by looking at how you've initialized the policies array, it's clearly case (b).
So, how does the evaluation ((*policies)[i]).IndividualFile go wrong?
*policies returns ptr0 from the diagram above.
That value is now subscripted, as ptr0[i].
The first indication of trouble is that you're only ever using policies[0], and then treating this value, ptr0, as a pointer to the first element of an array of full-sized policy pair objects, eg,
ptr0 -> [ ppair0 | ppair1 | ppair2 | ... ]
This is the array you're indexing. Except that ptr0 does not point to a sequence of policy pair objects, it points to exactly one such object. So, as soon as i is greater than zero, you're off referencing undefined memory.
The revised expression, policies[i]->IndividualFile, works like this:
policies[i] is equivalent to *(policies + i), and returns one of ptr0, ptr1, etc.
ptri->IndividualFile is equivalent to (*ptri).IndividualFile, and returns the base address of the file name for the ith policy pair.

Resources