typedef struct myStruct_t {
uint32_t value0;
uint16_t value1;
uint8_t value2;
char * string;
};
myStruct_t my_data;
void do_something(myStruct_t * data){
// Read value 0
if(data->value0 == 10){
// Whatever
}
}
void main (void){
do_something(&my_data);
}
Is it correct if I say that I am passing value of structure variable or memory location of structure variable into function instead of saying passing structure
What does it means pass structure into function in c language?
#include <stdio.h>
struct foo {
int x; /* Example member */
};
void bar(struct foo arg)
{
arg.x = 2;
}
struct foo baz(void)
{
struct foo arg;
arg.x = 1;
return arg;
}
int main(void)
{
struct foo example, another;
example = baz();
printf("First, example.x is %d.\n", example.x);
another = example;
bar(example);
printf("Then, example.x is %d and another.x is %d.\n", example.x, another.x);
return 0;
}
Compile and run it, and consider the output:
Consider the following program:Code: [Select]
struct foo baz(void)
{
struct foo arg;
arg.x = 1;
return arg;
}
Consider the following program:Code: [Select]
struct foo baz(void)
{
struct foo arg;
arg.x = 1;
return arg;
}
Here you are returning a struct that was allocated in the stack, this will lead to undefined behaviour and a crash if you are lucky.
3 If a return statement with an expression is executed, the value of the expression is
returned to the caller as the value of the function call expression. If the expression has a
type different from the return type of the function in which it appears, the value is
converted as if by assignment to an object having the return type of the function.
Consider the following program:Code: [Select]
struct foo baz(void)
{
struct foo arg;
arg.x = 1;
return arg;
}
Here you are returning a struct that was allocated in the stack, this will lead to undefined behaviour and a crash if you are lucky.
Consider the following program:Code: [Select]
struct foo baz(void)
{
struct foo arg;
arg.x = 1;
return arg;
}
Here you are returning a struct that was allocated in the stack, this will lead to undefined behaviour and a crash if you are lucky.
Consider the following program:Code: [Select]
struct foo baz(void)
{
struct foo arg;
arg.x = 1;
return arg;
}
Here you are returning a struct that was allocated in the stack, this will lead to undefined behaviour and a crash if you are lucky.
char *bad(void)
{
char buffer[24] = "Hello";
return buffer;
}
However, the following is completely acceptable:struct buffer {
char data[24];
};
struct buffer foo(void)
{
struct buffer b = { .data = "Hello" };
return b;
}
struct buffer bar(void)
{
return (struct buffer){ .data = "Hi from me too" };
}
Although the struct variable is instantiated/created in the function, it is not converted to a pointer like an array would be. Thus, we are not returning an address or even referring to any address; we are returning the structure by value. It is up to the compiler (and as I mentioned before, the details are agreed in whatever ABI is being used) to handle it correctly, but it has to handle it correctly to comply with the C standard –– remember, the C standard does not allow the compiler to treat a structure that contains an array like an array; a structure is a structure and is passed by value, not by reference, even if that structure contains one or more arrays.
[...] However, I understand why one would think it leads to undefined behaviour. [...]
struct ivec2d* ivec2d_bad(struct ivec2d v1, struct ivec2d v2) {
return &(struct ivec2d){ .x = v1.x - v2.x, .y = v1.y - v2.y };
}
Do not do this:Code: [Select]struct ivec2d* ivec2d_bad(struct ivec2d v1, struct ivec2d v2) {
return &(struct ivec2d){ .x = v1.x - v2.x, .y = v1.y - v2.y };
}
<source>: In function 'ivec2d_bad':
<source>:16:12: warning: function returns address of local variable [-Wreturn-local-addr]
16 | return &(struct ivec2d){ .x = v1.x - v2.x, .y = v1.y - v2.y };
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Fundamentally, that'd be a misunderstanding of what pointers are and what values are.
#include <stdint.h>
#define ACCESSOR_FUNCTION __attribute__ ((__always_inline__, __unused__)) static inline
ACCESSOR_FUNCTION uint32_t get_32le(const void *src) {
const unsigned char *const s = src;
return ((uint32_t)s[0])
| ((uint32_t)s[1] << 8)
| ((uint32_t)s[2] << 16)
| ((uint32_t)s[3] << 24);
}
ACCESSOR_FUNCTION uint32_t get_32be(const void *src) {
const unsigned char *const s = src;
return ((uint32_t)s[0] << 24)
| ((uint32_t)s[1] << 16)
| ((uint32_t)s[2] << 8)
| ((uint32_t)s[3]);
}
Note that the ACCESSOR_FUNCTION macro is there to tell the compiler that these really should be inlined, and it is okay if they are not used (and therefore do not actually generate any machine code in the resulting binary); but for exploration, one can simply define it to empty.
Here you are returning a struct that was allocated in the stack, this will lead to undefined behaviour and a crash if you are lucky.
This is such a common misconception. Why do you think it works like this? This is safe, and has always been safe.
Returning a pointer to it however, is not.
#include<stdio.h>
#include<stdlib.h>
struct buffer
{
struct buffer *N;
};
struct buffer *foo( struct buffer *Ptr )
{
struct buffer *qtr = malloc (sizeof(*qtr));
if (qtr == NULL)
{
printf("Memory not allocated.\n");
return 0;
}
qtr-> N = Ptr;
return qtr;
}
int main()
{
struct buffer *ptr = malloc (sizeof(*ptr));
if ( ptr == NULL )
{
printf("Memory not allocated.\n");
return 1;
}
ptr = foo ( ptr );
return 0;
}
how to figure out what happen in code by printing value of both ponter's in code ?
struct buffer *foo(struct buffer *ptr)
{
struct buffer *qtr = malloc(sizeof *ptr);
if (!qtr) {
fprintf(stderr, "Out of memory.\n");
exit(EXIT_FAILURE);
}
printf("qtr = %p, ptr = %p\n", (void *)qtr, (void *)ptr);
qtr->N = ptr;
return qtr;
}
[code]
or (adding [tt]#include <assert.h>[/tt] near the top of your program),
[code]
struct buffer *foo(struct buffer *ptr)
{
struct buffer *qtr = malloc(sizeof *ptr);
printf("qtr = %p, ptr = %p\n", (void *)qtr, (void *)ptr);
assert(qtr != NULL);
qtr->N = ptr;
return qtr;
}
assert() is a preprocessor macro, that causes the program to stop if the argument expression is false.how to figure out what happen in code by printing value of both ponter's in code ?You can use e.g.
printf("qtr = %p\n", (void *)qtr);
to print the address where pointer qtr points to.
#include<stdio.h>
#include<stdlib.h>
struct buffer
{
struct buffer *N;
};
struct buffer *foo( struct buffer *Ptr )
{
struct buffer *qtr = malloc (sizeof(*qtr));
if (qtr != NULL)
{
qtr-> N = Ptr;
printf("qtr hold memory location : %p \n",(void*) qtr);
}
return qtr;
}
int main()
{
struct buffer *ptr = malloc (sizeof(*ptr));
printf("ptr hold memory location : %p \n", (void*) ptr);
if ( ptr != NULL )
{
ptr = foo ( ptr );
printf("after calling, ptr hold memory location : %p \n", (void*) ptr);
ptr = foo ( ptr );
printf("after calling, ptr hold memory location : %p \n", (void*) ptr);
ptr = foo ( ptr );
printf("after calling, ptr hold memory location : %p \n", (void*) ptr);
}
return 0;
}
Or to draw an even worse picture if RISC-V takes off in the MCU industry: a rv32i processor does not require unaligned memory access support neither. But it leaves room to do it, so some may. It depends on the implementation if it is handled in invisibly in hardware (where it may cause slowdowns), handled with a software trap, or as a fatal exception. Although I support open-source designs going down through the ISA, I don't particularly like the "it may do this" (or it may not) aspect being part of the core spec. I sincerely hope that most COTS implementations settle on a sane common ground..
If you have access to the source code then I would suggest that you regard misaligned accesses as a bug. There are so many systems out there that don't support misaligned accesses that portable software got fixed decades ago.
If you aren't sure of the alignment of something then the easiest thing is to memcpy() it to a known-aligned variable. It's going to perform the most efficient series of loads and shifts for you (which hardware misaligned access has to do for you anyway). For a single variable that's less efficient than hardware misaligned support, but for an array it's probably more efficient.
how to figure out what happen in code by printing value of both ponter's in code ?You can use e.g.
printf("qtr = %p\n", (void *)qtr);
to print the address where pointer qtr points to.
why does qtr hold different memory location after each callCode: [Select]#include<stdio.h>
#include<stdlib.h>
struct buffer
{
struct buffer *N;
};
struct buffer *foo( struct buffer *Ptr )
{
struct buffer *qtr = malloc (sizeof(*qtr));
if (qtr != NULL)
{
qtr-> N = Ptr;
printf("qtr hold memory location : %p \n",(void*) qtr);
}
return qtr;
}
int main()
{
struct buffer *ptr = malloc (sizeof(*ptr));
printf("ptr hold memory location : %p \n", (void*) ptr);
if ( ptr != NULL )
{
ptr = foo ( ptr );
printf("after calling, ptr hold memory location : %p \n", (void*) ptr);
ptr = foo ( ptr );
printf("after calling, ptr hold memory location : %p \n", (void*) ptr);
ptr = foo ( ptr );
printf("after calling, ptr hold memory location : %p \n", (void*) ptr);
}
return 0;
}
ptr hold memory location : 00641230
qtr hold memory location : 00641260
after calling, ptr hold memory location : 00641260
qtr hold memory location : 00641270
after calling, ptr hold memory location : 00641270
qtr hold memory location : 00641280
after calling, ptr hold memory location : 00641280
printf("after calling, ptr hold memory location : %p \n", (void*) ptr->N);
You would find the "previous" box that's held by the larger box.why does qtr hold different memory location after each call
/* This function creates a new buffer structure.
The function takes one parameter, a pointer to a buffer structure.
The parameter is set as the N member of the new buffer structure.
The function returns a pointer to the new buffer structure.
*/
struct buffer *foo( struct buffer *Ptr )
{
struct buffer *qtr = malloc (sizeof(*qtr));
if (qtr != NULL)
{
qtr-> N = Ptr;
printf("qtr hold memory location : %p \n",(void*) qtr);
}
return qtr;
}
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct list list;
struct list {
struct list *next;
char data[]; /* Flexible Array Member (C99 or later). Only one allowed per struct, and must be last. */
};
/* Prepend new data to the beginning of the list.
The first parameter is a pointer to the variable that points to the first element in the list,
so that we can modify the value of that variable.
The second parameter is the string to store in the new list element.
*/
void list_prepend(list **rootptr, const char *data)
{
/* rootptr must be a valid pointer to a variable of the list type. */
if (rootptr == NULL) {
fprintf(stderr, "list_prepend(): NULL pointer to list pointer variable!\n");
exit(EXIT_FAILURE);
}
/* We also need a valid string; an empty string is okay, but a NULL is not. */
if (data == NULL) {
fprintf(stderr, "list_prepend(): NULL data pointer, not a string!\n");
exit(EXIT_FAILURE);
}
const size_t datalen = strlen(data); /* Number of chars in data */
/* Allocate the list element, with sufficent room for the data (as a 'flexible array member'),
plus the end-of-string character '\0'. */
list *element = malloc (sizeof (list) + datalen + 1);
if (!element) {
fprintf(stderr, "list_prepend(): Out of memory.\n");
exit(EXIT_FAILURE);
}
/* If the string is not empty, copy it, */
if (datalen > 0)
memcpy(element->data, data, datalen);
/* but make sure the data is always properly terminated with an end-of-string character. */
element->data[datalen] = '\0';
/* Prepend to the given list. */
element->next = *rootptr;
*rootptr = element;
}
/* Free an entire list, starting at the specified list element.
*/
void list_free(list *element)
{
while (element) {
/* Before we destroy this element, we need to grab the pointer to the next element first. */
list *current = element; /* This we will destroy, */
element = element->next; /* and next loop iteration will worry about the next element. */
/* This is called "poisoning". Its purpose is to make it easier to detect use-after-free() bugs,
by making the members "invalid" or uncommon, easily detectable values ("poison"). */
current->next = NULL;
current->data[0] = '\0'; /* Note: This assumes we always reserve room for data! */
/* Now that we've made the list element useless or "poisoned", we free it. */
free(current);
}
}
/* Write a Graphviz DOT language description of the list to the specified stream.
*/
static void list_dot_recurse(FILE *out, list *ptr);
void list_dot(FILE *out, list *root, const char *initial)
{
/* If out is not a valid stream, do nothing, just return immediately. */
if (!out)
return;
/* If we have no list nor an initial node, do nothing. */
if (!root && !initial)
return;
fprintf(out, "digraph {\n");
fprintf(out, " rankdir = LR;\n"); /* Prefer left-to-right. */
/* If we have an initial node, we draw it as a rectangle. */
if (initial)
fprintf(out, " initial [ shape=\"rect\", label=\"%s\" ];\n", initial);
/* If we have a list, recursively output the description of the list itself. */
if (root)
list_dot_recurse(out, root);
/* If we have an initial node and a list, add an edge (arrow) from initial to the list. */
if (initial && root)
fprintf(out, " initial -> \"%p\";\n", (void *)root);
fprintf(out, "}\n");
}
static void list_dot_recurse(FILE *out, list *ptr)
{
/* Draw the data node with an oval, and the data value inside it. */
fprintf(out, " \"%p\" [ shape=\"oval\", label=\"%s\" ];\n", (void *)ptr, ptr->data);
/* If this is not the final node, recursively describe the following nodes. */
if (ptr->next) {
list_dot_recurse(out, ptr->next);
/* And draw the edge from the current node to the next node. */
fprintf(out, " \"%p\" -> \"%p\";\n", (void *)ptr, (void *)(ptr->next));
}
}
int main(void)
{
/* We use 'foo' to point to the first element in the list. */
list *foo = NULL;
/* Prepend some numbers to the list.
Note that we need to pass a pointer to the pointer to the first element in the list,
in this case a pointer to the variable foo. */
list_prepend(&foo, "one");
list_prepend(&foo, "two");
list_prepend(&foo, "three");
list_prepend(&foo, "four");
list_dot(stdout, foo, "pointer foo");
list_free(foo);
return EXIT_SUCCESS;
}
To throw you directly into the deep end, consider the following singly-linked list example:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *nextNode;
};
void addNode(int value )
{
struct node *newNode = NULL;
newNode = malloc (sizeof(*newNode));
if (newNode != NULL)
{
newNode -> data = value;
newNode -> nextNode = NULL;
}
}
int main()
{
addNode( 2 );
return 0;
}
newNode -> nextNode = NULL;