I am trying to understand why the following code compiles and runs fine. I would expect any assignment using data inside f not to compile with a gcc error assignment of member āiā in read-only object. Is there some kind of exception, because data.i is allocated dynamically?
#include <stdio.h>
#include <stdlib.h>
struct a {
int *i;
};
void f(const struct a *data) {
data->i[0] = 55;
}
int main() {
struct a data;
data.i = malloc(2 * sizeof(int));
f(&data);
printf("%d\n", data.i[0]);
return 0;
}
const front of a struct will make it read-only. If the struct contains pointer members, then those pointers themselves will turn read-only. Not what they point at.
That is, const struct a will make the member i behave is if it was declared as int *const i;, meaning that the pointer itself cannot be changed to point elsewhere. The pointed-at data is still of read/write int though.
If you want to restrict access to i inside a function, you should make that function take a const int* parameter and pass the i member to that function.
In the below code, const indicates what data points to is not to be modified. data->i[0] = 55; does not modify the pointer data->i. Instead that line of code modifies the memory pointed to by data->i. This is allowed as pointer .i is int * and not const int *.
struct a {
int *i;
};
void f(const struct a *data) {
data->i[0] = 55;
}
You cant modify i but you can modify the objects referenced by i.
To prevent it you need to:
struct a {
const int *i;
};
Related
can you please explain in details this line of code inside struct:
There is a pointer to function but why would you reference it to struct?
void (*function)(struct Structure *);
what does this mean
(struct Structure *)?
(struct Structure *)
It means that the function have a struct Structure * argument. Actually it will make more sense with (struct Structure *variable of struct).
In this way, you can use a pointer to point a struct and should put the address of the struct variable which can be used in the function.
#include <stdio.h>
typedef struct circle{
int rad;
int area;
} Circle;
void ShowCircleInfo(Circle *info)
{
printf("rad value: %d\n", info->rad);
printf("area value: %d", info->area);
}
int main(void)
{
Circle circle_one;
circle_one.rad = 2;
circle_one.area = 3;
ShowCircleInfo(&circle_one);
return 0;
}
void (*function)(struct Structure *); declares function to be a pointer to a function that has a parameter of type struct Structure * and does not return a value.
For example
#include <stdio.h>
struct Structure {
int a;
void (*function)(struct Structure *);
};
void foo(struct Structure *a) {
if (a->function == NULL) a->function = foo;
a->a++;
printf("%d\n", a->a);
}
int main(void) {
struct Structure a = {42, foo};
struct Structure b = {0}; // don't call b.function just yet!!
a.function(&b); // foo(&b)
b.function(&a); // foo(&a)
}
See code running at https://ideone.com/7E74gb
In C, function pointer declarations have almost the same structure as function headers.
Only the function name will change to have some parantheses and a "*" in it, and the arguments won't have names, because only their types are important when using pointers (we don't access the values of the arguments, so we don't need their names).
They basically look like this:
<return_value> (*<function_name>)(<argument_list>)
So, for example, the function pointer for the function
void swap(int* a, int* b);
would be
void (*swap_ptr)(int*, int*);
Notice that the name of the pointer is in the place of the name of the function, and looks a bit odd compared to normal pointer declarations.
An excellent reading on this topic (you can skip the C++ stuff): https://www.cprogramming.com/tutorial/function-pointers.html
Am I allowed to use a variable being initialized inside a designated initializer?
Consider the following listing:
struct A {
int a;
int * const a_ptr;
};
struct A foo(int a) {
struct A result = {
.a = a,
.a_ptr = &result.a
};
return result;
}
demo
Am I allowed to use result in this designated initializer expression? Is this behavior defined? Is this code portable?
Update
My bad, the example contains a potential stack corruption. The listing should be:
struct A {
int a;
int * const a_ptr;
};
void foo(int a) {
struct A result = {
.a = a,
.a_ptr = &result.a
};
bar(&result);
}
The initialization by itself is fine.
At the time result is declared, its address (as well as the addresses of its fields) is constant. So it is safe to use &result.a in the initializer of result.
What is a problem however is that you're returning a copy of this structure. This copy contains the address of a local variable that no longer exists, so attempting to use the value of the a_ptr member of the returned struct will trigger undefined behavior.
The question has changed completely, here is my new answer:
Your code is fine, you can check this, it won't assert on any platform.
You pass the pointer to the local variable result to bar. In bar that local variable still exists p points to that variable (result). Therefore the a_ptr still points to result.a.
But I'm just wondering what you're trying to achieve here.
#include <assert.h>
struct A {
int a;
int* const a_ptr;
};
void bar(struct A *p)
{
assert(p->a_ptr == &p->a);
}
void foo(int a) {
struct A result = {
.a = a,
.a_ptr = &result.a
};
bar(&result);
}
int main()
{
foo(2);
}
BTW:
struct A result = {
.a = a,
.a_ptr = &result.a
};
is equivalent to this:
struct A result;
result.a = a;
result.a_ptr = &result.a;
but for latter you'd need to declare int* a_ptr; instead of int* const a_ptr;.
I have two structs pbuf and netif, and assigned two variables (local_pbuf, local_netif) with them. These variables hold some data. There is another struct called wrapper_p_n, which holds two pointers of the type pbuf and netif. My goal is to write a function which hand over the variables local_pbuf and local_netif by call by reference and then wraps the two pointers in a single struct called wrapper_p_n. Then I want to use call by reference to give wrapper_p_n to another function. Unfortunately I get the Error message:
[Error] cannot convert 'pbuf**' to 'pbuf*' in assignment
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
struct pbuf{
int a;
int b;
};
struct netif{
int c;
int d;
};
struct wrapper_p_n{ // wrapper for pbuf- and netif-struct pointer
struct pbuf *wp_val_p;
struct netif *wp_val_n;
};
void rx_local_p_n(struct pbuf *rx_pbuf, struct netif *rx_netif)
{
// wrap the received pointer
struct wrapper_p_n *local_w_p_n;
local_w_p_n->wp_val_p = &rx_pbuf;
local_w_p_n->wp_val_n = &rx_netif;
/*Passing *local_w_p_n pointer to another function: Example: */
/*ex_function(&local_w_p_n)*/
}
int main(int argc, char** argv) {
// give values to local_pbuf and netif
struct pbuf local_pbuf;
local_pbuf.a = 1;
local_pbuf.b = 2;
struct netif local_netif;
local_netif.c = 3;
local_netif.d = 4;
//passing pbuf- and netif-stuct to function
rx_local_p_n(&local_pbuf, &local_netif);
return 0;
}
In the function void rx_local_p_n you pass in pointers to the pbuf and netif struct. These are already pointers and do not need to be assigned to your wrapper struct using the address of operator (&): by doing so you are getting the memory location of the pointer itself. That is why it is complaining about not being able to convert pbuf** to pbuf*.
Solution
local_w_p_n->wp_val_p = &rx_pbuf; to local_w_p_n->wp_val_p = rx_pbuf;
local_w_p_n->wp_val_n = &rx_netif; to local_w_p_n->wp_val_n = rx_netif;
Here in the function params,
struct pbuf *rx_pbuf, struct netif *rx_netif
Are already pointers, you do not need to get the address of the pointers, the & is useful when your variables are allocated on the stack and the function call needs a pointer.
As a result, this is the code change
local_w_p_n->wp_val_p = rx_pbuf;
local_w_p_n->wp_val_n = rx_netif;
In the original posted code local_w_p_n was defined as a pointer but not initialized; the attempts to assign members should crash since local_w_p_n would be leftover stack data, not a valid address. Try this example:
void rx_local_p_n(struct pbuf *rx_pbuf, struct netif *rx_netif)
{
// define as a struct instead of a struct *
struct wrapper_p_n local_w_p_n;
// assign from func args without &
// switch from -> to .
local_w_p_n.wp_val_p = rx_pbuf;
local_w_p_n.wp_val_n = rx_netif;
x_function(&local_w_p_n);
}
I have a C code, somewhat similar to this:
struct st
{
int *var;
}
void fun(st *const ptr)
{
// considering memory for struct is already initialized properly.
ptr->var = NULL; // NO_ERROR
ptr = NULL; // ERROR, since its a const pointer.
}
void main()
{
//considering memory for struct is initialized properly
fun(ptr);
}
I dont want to declare int *var as const in the structure definition, so as not to mess with the huge code base. Not looking to make any change in the structure definition
Is there any way in C, to get an error for the NO_ERROR line
ptr->var = NULL; // NO_ERROR ?
Just declare the parameter with const, so the ptr is a pointer to a const object:
void fun(const struct st* ptr)
Your declaration makes ptr to be constant, but not the object to which it points. Also don't miss struct keyword
void fun(struct st *const ptr);
Instead you should use
void fun(const struct st *ptr);
Such declaration allows to change pointer but not the object to which it points.
Keep this in mind:
With type* const ptr, you cannot change the pointer but you can change the pointed data
With const type* ptr, you can change the pointer but you cannot change the pointed data
So all you need is to replace struct st* const ptr with const struct st* ptr.
Superb! Thank you so much guys!
I did this -
void fun(const struct st *const ptr);
and I was able to get an error while changing both ptr and ptr->var .. Just what I needed..
I want my struct to carry a string. I defined it like so:
typedef struct myStruct {
char* stringy
} myStruct
and a function
free(char *stringy){
//structObj is a struct object
structObj->stringy = stringy
}
Is this correct? I have a feeling that since it's a local variable, stringy will be lost, and the pointer will point to garbage.
Sorry, new with C.
It would be garbage if you were somehow using char** stringy, but structObj->stringy = stringy means "you know the thing that stringy points to? Now structObj->stringy points to that". Of course, it is still possible to unset the value which the pointer is pointing to, and at that point dereferencing will yield garbage.
Here's an example to make it clearer:
#include<stdio.h>
typedef struct mStruct {
char* stringy;
} myStruct;
myStruct * structObj;
void doSomething(char* stringy)
{
structObj->stringy = stringy;
}
int main(int argc, char* argv)
{
char* a = "abc\n";
structObj = malloc(sizeof(myStruct));
doSomething(a);
a = "qxr\n";
printf(structObj->stringy);
}// prints "abc\n"
If stringy is defined in callers of free function, as long as they keep the actual string in its place (where stringy points), no problem.
There is not any local variable declaration in your code.
You have to declare:
typedef struct myStruct {
char* stringy
} myStruct;
free(char *stringy){
myStruct *structObj;
structObj->stringy = stringy;
}
Pay attention to the semicolon that I've added to the end of the typedef declaration.
This was not not in your code.
The object structObj is a struct whose type is myStruct.
Now, your parameter stringy comes from another site, it is not lost.
But the struct structObj will have duration only inside your "free" function.
EDIT
I have fixed an error: the right declaration has to be "pointer to structObj", which is done in this way:
myStruct *structObj;
Observe that now myStruct is a non-initialized pointer, so the following assignment is legal:
structObj->stringy = stringy;
but will not work.
However I think this goes beyond the scope of the original question...
myStruct is type which you defined for your struct myStruct .that to you need to create an object before using.
you need to do like this:
typedef struct myStruct {
char *stringy;
} myStruct_t; //user defined data type
myStruct_t *obj;
// you need to allocate memory dynamically.
obj= (myStruct_t *) malloc(sizeof(myStruct_t));
usage:
scanf("%s",obj->stringy);
printf("%s",obj->stringy);
in function:
my_free(char *str) //str is local string
{
obj->stringy=str;
}
your can also try this code :
typedef struct myStruct {
char stringy[20]; //char *stringy
} myStruct_t; //user defined data type
myStruct_t obj; //object creation
usage:
scanf("%s",obj.stringy);
printf("%s",obj.stringy);
in function:
my_free(char *str) //str is local string
{
strcpy(obj.stringy,str);
}
You're correct that as soon as what it points to goes out of scope, it will point to garbage: this is a dangling pointer. You'll need to allocate some memory and perform a copy to fix this:
add_string(my_struct* s, const char* c)
{
size_t len = strlen(c);
s->file = malloc(len + 1);
strcpy(s->file, c);
}
Don't forget that you'll need to free it when you're done:
void destroy_struct(my_struct* s)
{
free(s->file);
free(s);
}