Safely copying `const char *` into struct pointer - c

I'm trying to create an instance of a struct with a const member.
Because the member is const, I'm creating a temporary value that has it initialized explicitly.
#include <string.h>
#include <stdlib.h>
typedef struct Thing {
const char *value;
} Thing;
void createThing(const char *value) {
// Create a temporary instance of Thing to initialize the const value
Thing temporary = {
.value = value
};
// Create a new thing
Thing *thing = (Thing *)malloc(sizeof(Thing));
if(thing == NULL)
return NULL;
// Copy the contents of temporary into the result
memcpy(thing, &temporary, sizeof(Thing));
// Return the result
return thing;
}
Is it safe to use value this way, or should I create a new copy? For example:
const char *valueCopy = (char *)malloc(sizeof(char) * (strlen(value) + 1));
strcpy(valueCopy, value);
My reasoning is that the argument value will fall out of scope after the function call ends, and without copying, the value in the struct will become invalid.
As a side-note, I think I'm doing the right thing by copying from a temporary struct, but glad to be told otherwise.

Leaving aside the side issue of constness, the question exhibits an essential misunderstanding. Here:
Is it safe to use value this way, or should I create a new copy? For
example:
const char *valueCopy = (char *)malloc(sizeof(char) * (strlen(value) + 1));
strcpy(valueCopy, value);
My reasoning is that the argument value will fall out of scope after
the function call ends, and without copying, the value in the struct
will become invalid.
Although it is true that function parameter value goes out of scope when execution leaves the function, that's irrelevant. The first proposed alternative initializes a structure member from the value of value. The structure member is a separate object from the function parameter. The assignment makes that object refer to the same data that value does. It does not make the member an alias for value itself. The structure member has its own lifetime, separate from and (in this case) unrelated to the lifetime of the value parameter. In that sense, then, yes, it is safe to use value as you do in the first code snippet.
HOWEVER, there are other reasons why you might want to make a copy of the pointed-to data, as well as reasons why you might want to avoid doing that. It's unclear from the question which is appropriate in your particular case. But all this is independent of the constness of the member.

Related

Difference between modifying a function parameter and modifying a local variable

I saw a function that takes a list and a function pointer, and applies this
function to each element of the list.
ft_list.h
#ifndef LIST_H
#define LIST_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct s_list
{
struct s_list *next;
void *data;
} t_list;
#endif
ft_list_foreach.c
void ft_list_foreach(t_list *begin_list, void (*f) (void *))
{
t_list *curr;
curr = begin_list;
while (curr)
{
(*f)(curr->data);
curr = curr->next;
}
}
But why declare t_list *curr ? And not just increment begin_list until the end of the linked list(NULL) ?
Although in this case declaring a new variable which holds the pointer to the list makes no difference, I would say that this is a good practice to never mutate the function parameters, only when the function's nature requires to do so (i.e. when you have an inout parameter, like a buffer). This unwritten rule will save you from a lot of problems in future when dealing with more complex functions.
Consider just a simple case where you would need for some reason to also destroy and free the contents of this list after applying the f function. Of course, in this simple example you would easily spot the issue, but there are cases when this wouldn't be that obvious.
So, again, even though here it makes no difference, I strongly recommend to always write your functions using this pattern and this will avoid a lot of weird and unexpected issues.
A function can be designed to return a value, although there is technically no explicit need to so, when passing a pointer to an object
as argument to modify it in the function.
The reason for this is when you have a critical operation inside of the function, and there is an error with this operation, you can return a specific value to the caller to symbolize that an error occurred inside of the function.
I guess the author later (half) optimized the code of the function here as his/her first intent maybe was to add such a security mechanism or even prepare the code to maybe later add this if the function becomes more critical features.
It is a technique that you return the passed pointer, when the operations in the function were successful and f.e. NULL at an error.
Also a common technique is to reassign the passed pointer with the returned pointer value, although this is risky since you lose the reference in the caller completely if an error occurred in the called function.
Since you increment the pointer in the function, it would be not very good to return the incremented pointer as one might want to reassign the passed pointer with the return value, like:
int *p = //anything ;
p = foo(p);
You need to either store the passed pointer value inside of another separate pointer variable, increment this "copy" pointer and return the passed parameter variable
OR
store the value of the passed pointer into another local pointer variable, increment the parameter pointer and return the "copy" pointer.
Therefore it can make sense to use curr instead of begin_list to increment and use begin_list as return value at success.
Otherwise NULL if an error occurred.
Note that you need to change the return type from void to t_list * then.
Also:
Difference between modifying a function parameter and modifying a local variable
A parameter is a local variable.

Why are pointers such a big deal in C?

I understand the premise of pointers, but I find it very annoying, and I don't get why it's considered useful;
I've learned about pointers, and the next thing I know, I start seeing bubbles, asterisks, and ampersands everywhere.
#include <stdio.h>
int main () {
int *ptr, q;
q = 50;
ptr = &q;
printf("%d", *ptr);
return 0;
}
why is this important or useful?
First, parameters passed to a function can only be primitives(int, char, long....), structs or pointers. Then if you need to pass a more complex element like an array (strings) or a function, you have to pass a reference to this element.
The second things that I can quickly think of is: parameters are always passed by "value". This means the called function only get a copy of your variable. So, modifications will only affect the copy, the original variable will remain unchanged.
If you pass a variable by "reference" with a pointer, the pointer itself is immutable but as it is a reference to the original var, any modification to the pointed element will also affect the var in the caller function.
In other words, if you want to create a function that can alter a variable, you have to pass it a pointer to that variable to achieve this.

Is it possible to define a pointer without a temp/aux variable? (Or would this be bad C-coding?)

I'm trying to understand C-pointers. As background, I'm used to coding in both C# and Python3.
I understand that pointers can be used to save the addresses of a variable (writing something like type* ptr = &var;) and that incrementing pointers is equivalent to incrementing the index of an array of objects of that object type type. But what I don't understand is whether or not you can use pointers and deferenced objects of the type (e.g. int) without referencing an already-defined variable.
I couldn't think of a way to do this, and most of the examples of C/C++ pointers all seem to use them to reference a variable. So it might be that what I'm asking is either impossible and/or bad coding practice. If so, it would be helpful to understand why.
For example, to clarify my confusion, if there is no way to use pointers without using predefined hard-coded variables, why would you use pointers at all instead of the basic object directly, or arrays of objects?
There is a short piece of code below to describe my question formally.
Many thanks for any advice!
// Learning about pointers and C-coding techniques.
#include <stdio.h>
/* Is there a way to define the int-pointer age WITHOUT the int variable auxAge? */
int main() // no command-line params being passed
{
int auxAge = 12345;
int* age = &auxAge;
// *age is an int, and age is an int* (i.e. age is a pointer-to-an-int, just an address to somewhere in memory where data defining some int is expected)
// do stuff with my *age int e.g. "(*age)++;" or "*age = 37;"
return 0;
}
Yes, you can use dynamic memory (also known as "heap") allocation:
#include <stdlib.h>
int * const integer = malloc(sizeof *integer);
if (integer != NULL)
{
*integer = 4711;
printf("forty seven eleven is %d\n", *integer);
free(integer);
// At this point we can no longer use the pointer, the memory is not ours any more.
}
This asks the C library to allocate some memory from the operating system and return a pointer to it. Allocating sizeof *integer bytes makes the allocation fit an integer exactly, and we can then use *integer to dereference the pointer, that will work pretty much exactly like referencing an integer directly.
There are many good reasons to use pointers in C, and one of them is, that you can only pass by value in C - you cannot pass by reference. Therefore passing pointer to an existing variable saves you the overhead of copying it to stack. As an example, let's assume this very large structure:
struct very_large_structure {
uint8_t kilobyte[1024];
}
And now assume a function which needs to use this structure:
bool has_zero(struct very_large_structure structure) {
for (int i = 0; i < sizeof(structure); i++) {
if (0 == structure.kilobyte[i]) {
return true;
}
}
return false;
}
So for this function to be called, you need to copy the whole structure to stack, and that can be especially on embedded platforms where C is widely used an unacceptable requirement.
If you will pass the structure via pointer, you are only copying to the stack the pointer itself, typically a 32-bit number:
bool has_zero(struct very_large_structure *structure) {
for (int i = 0; i < sizeof(*structure); i++) {
if (0 == structure->kilobyte[i]) {
return true;
}
}
return false;
}
This is by no mean the only and most important use of pointers, but it clearly shows the reasoning why pointers are important in C.
But what I don't understand is whether or not you can use pointers and deferenced objects of the type (e.g. int) without referencing an already-defined variable.
Yes, there are two cases where this is possible.
The first case occurs with dynamic memory allocation. You use the malloc, calloc, or realloc functions to allocate memory from a dynamic memory pool (the "heap"):
int *ptr = malloc( sizeof *ptr ); // allocate enough memory for a single `int` object
*ptr = some_value;
The second case occurs where you have a fixed, well-defined address for an I/O channel or port or something:
char *port = (char *) OxDEADBEEF;
although this is more common in embedded systems than general applications programming.
EDIT
Regarding the second case, chapter and verse:
6.3.2.3 Pointers
...
5 An integer may be converted to any pointer type. Except as previously specified, the
result is implementation-defined, might not be correctly aligned, might not point to an
entity of the referenced type, and might be a trap representation.67)
67) The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to
be consistent with the addressing structure of the execution environment.
Parameters to a function in C are always pass by value, so changing a parameter value in a function isn't reflected in the caller. You can however use pointers to emulate pass by reference. For example:
void clear(int *x)
{
*x = 0;
}
int main()
{
int a = 4;
printf("a=%d\n", a); // prints 4
clear(&a);
printf("a=%d\n", a); // prints 0
return 0;
}
You can also use pointers to point to dynamically allocated memory:
int *getarray(int size)
{
int *array = malloc(size * sizeof *array);
if (!array) {
perror("malloc failed");
exit(1);
}
return array;
}
These are just a few examples.
Most common reason: because you wish to modify the contents without passing them around.
Analogy:
If you want your living room painted, you don't want to place your house on a truck trailer, move it to the painter, let him do the job and then haul it back. It would be expensive and time consuming. And if your house is to wide to get hauled around on the streets, the truck might crash. You would rather tell the painter which address you live on, have him go there and do the job.
In C terms, if you have a big struct or similar, you'll want a function to access this struct without making a copy of it, passing a copy to the function, then copy back the modified contents back into the original variable.
// BAD CODE, DONT DO THIS
typedef struct { ... } really_big;
really_big rb;
rb = do_stuff(rb);
...
rb do_stuff (really_big thing) // pass by value, return by value
{
thing->something = ...;
...
return thing;
}
This makes a copy of rb called thing. It is placed on the stack, wasting lots of memory and needlessly increasing the stack space used, increasing the possibility of stack overflow. And copying the contents from rb to thing takes lots of execution time. Then when it is returned, you make yet another copy, from thing back to rb.
By passing a pointer to the struct, none of the copying takes place, but the end result is the very same:
void do_stuff (really_big* thing)
{
thing->something = ...;
}

Pointers - confusion

I'm wondering if it is always better to use pointers. I have a structure with only one byte (or some integers ).
This structure contains i.e. parameters to a routine and will be passed there.
If I don't use pointers (inside of the struct), but pass this struct by pointer, would the change (for logPrio) made in main_loop be visible outside (i.e in main)?
Please see this sample to get me:
typedef struct mainloop_param_t
{
unsigned char *logPriop;
//or versin w/o pointer
unsigned char logPrio;
}mainloop_param_t;
int main()
{
mainloop_param_t mlparams;
unsigned char logPrio;
mlparams.logPriop = &logPrio;
// or nothing cause mlparams.logPrio already initialized
// would mlparams.logPrio be a copy or original?
g_timeout_add (5000, (GSourceFunc)main_loop, &mlparams);
}
If I don't use pointers (inside of the struct), but pass this struct by pointer, would the change (for logPrio) made in main_loop be visible outside (i.e in main)?
Yes, after you have passed the address of mlparams, every change made in main_loop can be visible in main, regardless of whether a pointer or an variable inside mlparams.
I guess your probloem is when a pointer should be used. In my opinion, pointer is just a tool to access data, it should not be a problem of itself. The important things are "which place the data should be?" and "how does programs access the data?"
The followings are parts of usages:
data is here(locally) and will be accessed here --> just define and use an local variable
data in somewhere(another scope, e.g. outside) and will be accessed here --> define a pointer that point to the data and access tha data via operator *
data is here and will be accessed in somewhere(another scope, e.g. inside) --> define an variable and pass the address of the variable somewhere
data in somewhere and will be accessed in otherwhere --> define a pointer that point to the data and pass the pointer otherwhere
sometimes you need some data that may be in a large amout, insdead of copying all of them to stack(might cause overflow), it's better to copy an address of the beginning of the data. The copy of the address is just a pointer.
I'm wondering if it is always better to use pointers.
Use pointers when it is needed. Unnecessarily use of it may cause some confusion later to you and others readers.
If I don't use pointers, would the change (for logPrio) made in main_loop be visible outside (i.e in main)?
In case of global variable and structs YES, Otherwise NO.
unsigned char logPrio;
mlparams.logPriop = &logPrio;
In this code, it doesn't make any sense to use a pointer. The change happens in main and will be visible to g_timeout_add since you pass this struct to that function.
I think you are confusing things with how parameters are passed by pointer to a function. If you have a function like
void func (int x)
{
x = 2;
}
then the original variable passed to the function is not altered, because x inside the function is a copy of the variable from the caller.
int var = 1;
func(var);
printf("%d", var); // will print 1
If you want to alter the variable's value, you would have to write the function like:
void func (int* x)
{
*x = 2;
}
int var = 1;
func(&var);
printf("%d", var); // will print 2

Using the &-operand when passing a pointer to a function?

int enter_path(char** path) {
char* standard = "./questions.txt";
printf("\n\t%s\n\t%s",
"Please enter the file location.", "path: ");
fgets(*path, MAX_PATH_LENGTH ,stdin);
*(*path + (strlen(*path)-1) ) = '\0';
if(**path == '\n' )
*path = strdup(standard);
return 0;
}
int main(void){
char* path = malloc(MAX_PATH_LENGTH);
enter_path(&path);
some_other_function_using_the_path_string(path);
}
the code above works fine, the reason why i'm posting this is the following.
Why do i have to pass the adress of the pointer "path" to the function enter_path, so some other function can use/read the modified value.
So in short, Why do i have to use the &-operand when calling the "enter_path" function, and can't define enter_path as "int enter_path(char* path);"
I know this is normal variables refering to datatypes like int, long, etc.
but i assumed that when working with pointers the change should be visible for every other function. cause the pointer still referes to the same point in the memory, just the value has been changed.
Could it be i'm seeing this all wrong?
PS: I'm trying my best to keep my code ansi-C compliant, which is the reason i'm using fgets instead of readline. Just sayin that cause i've allready got some comments regarding the fact that the readline function is easier/safer to use.
With kind regards,
JD
If you have a variable of type T that you want a function to be able to modify, you need to pass it via a pointer, i.e.:
void foo(T *p) { *p = 42; }
int main(void) {
T t;
foo(&t);
// The value of t is now 42
}
In your code, T is char *; in other words, your function needs to be able modify a pointer, so you need to pass it a pointer to that pointer.
However, this is not good code. If (**path == '\n') is true, then you will leak memory.
The reason is that if you specify the parameter type as char *, you will operate on a copy of the pointer in the function, so your code (modified for this scenario)
path = strdup(standard);
Would not reflect back in the caller after the function ends
By passig the address of the variable, you can change the pointed-to pointer and this change will persist even after the function returns
Think of the pointer as your data (just like with int, etc.) by passing a char * pointer you can modify the pointed-to characters; by passing a char ** pointer, you can modify the pointed-to pointer (with the modification reflecting in the caller function as well).
You are passing a variable path that is itself a pointer.
But you are modifying the pointer itself in the function enter_path, hence you will have to pass the pointer to path and hence the address of path is to be passed and hence &path is passed.
In the current scenario, the line
*path = strdup(standard);
it does modify the variable path in the function but it's value will not change outside the function, i.e. in function main.

Resources