C variable assignment to array element - c

Quick question on how a variable is assigned the value of an array element. Trying to make sure my code uses minimal memory.
If I have a predefined array of structs and want to create a reference to one element of the array, how do I create the variable so that it's passed by reference as opposed to value? I've searched around for this but perhaps my search string isn't what it needs to be.
for instance
#myfile.h
typedef struct {
uint8_t abba;
uint8_t zabba;
} mystruct;
extern mystruct mystructs[2];
#myfile.c
mystruct mystructs[2] = {
{.abba=0,.zabba=1},
{.abba=2,.zabba=3}
};
void myfunc1() {
mystruct ms1 = mystructs[1];
printf("%d", ms1.abba);
ms1.zabba = 5;
}
void myfunc2() {
printf("%d", mystructs[1].abba);
mystructs[1].zabba = 5;
}
So my questions are as follows:
When I create ms1 in myfunc1, is it just a reference to mystructs[1]? or does it copy the element into ms1?
Will myfunc1 and myfunc2 yield the same results in memory usage?
will ms1.zabba = 5 actually update mystructs[1].zabba?

When I create ms1 in myfunc1, is it just a reference to mystructs[1]?
No, it's a copy.
or does it copy the element into ms1?
Yes.
Will myfunc1 and myfunc2 yield the same results in memory usage?
No. (To be more elaborate: myfunc1 creates a local object of type mystruct ("on the stack"); after leaving the function everything is back as before, so no harm done. The structs are not big, so no problem. On PCs you could get a problem with things that are big (MBs) or expensive (e.g. socket connections).)
will ms1.zabba = 5 actually update mystructs[1].zabba?
No, since ms1 is a copy.
You may want to use pointers or references.

It's a copy. You need to use a pointer to actually modify the remote struct :
void myfunc1() {
mystruct *ms1 = &mystructs[1];
printf("%d", ms1->abba);
ms1->zabba = 5;
}

Related

Struct by value in loop

Say I have a function from another api that returns structs by value
struct foo{
int bar;
bool success;
}
foo getThefoo();
What happens in a loop if this function is called eg
int foolen = 0;
foo** foos;
do {
foolen++;
foos = realloc(foos,sizeof(foo*)*foolen);
foo myfoo = getThefoo();
foos[foolen-1]=&myfoo;
}while (/**something*//)
Does a new foo struct get allocated on the stack for each iteration?. Or is the initial allocation reused?. I ask because taking a pointer to that structure might be an unexpected value.
getThefoo is defined in an external library. So its not trivial to make that return a pointer to a food structure.
This won't work, you're storing the address of a local which will go out of scope, rendering the stored addresses useless.
The proper fix seems to be to not store pointers to struct foos in the array, but just storing them directly:
struct foo *foos = NULL;
size_t foolen = 0;
do {
++foolen;
foos = realloc(foos, foolen * sizeof *foos);
foos[foolen - 1] = getTheFoo();
} while(something something);
Of course, the usual caveats apply:
It's more efficent to call realloc() less often, by over-allocating and tracking array length and array allocated space separately.
realloc() can fail, the above loses the old allocation (if any) when that happens.
Note that structures are values and thus fully assignable, so that's what we do.

Reducing the size of returned/passed data structures in C

I am taking the operating system class in mit online, I completed the first assignement http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-828-operating-system-engineering-fall-2012/assignments/MIT6_828F12_assignment1.pdfbut what surprised me is how they return the data structures, they work with a data structure and they return a smaller data structure, and to use it they just cast it back. I see that it can optimize the code but is this safe ? is it good practice ?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct small
{
int n ;
};
struct big
{
int n ;
char * string ;
};
struct small* f()
{
struct big* x = malloc(sizeof(struct big));
x->n = 'X';
x->string = strdup("Nasty!");
return (struct small*) x ;
}
int main(int argc, char *argv[])
{
struct big *y = (struct big*)f();
printf("%s\n",y->string);
}
EDIT 1 : here is the link from mit, i just replicated the idea in my own code.
http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-828-operating-system-engineering-fall-2012/assignments/sh.c
No structure is returned, but a pointer to a structure. A pointer contains the address of the memory where the actual object is located. (In this case it has been allocated dynamically with malloc, hence has dynamic storage duration and will live until the pogram ends or a free is called on the pointer.)
The code is legal and has defined semantics. 6.3.2.3/7 of the n1570 draft says
A pointer to an object type may be converted to a pointer to a
different object type. If the resulting pointer is not correctly
aligned for the referenced type, the behavior is undefined. [does not apply here. -ps]
Otherwise, when converted back again, the result shall compare equal
to the original pointer.
Note that the structures could be completely unrelated (the first data element does not need to be the same type). The cast could even be to a built-in type like int.
The issue may be different if the object were accessed through a pointer of the wrong type (which it isn't) because of aliasing issues.
To answer your questions:
Is it safe?
Obviously not. Just casting the type of a pointer to something else is something you should only do if you are positively sure it's the right type.
However, if you know that, everything is fine.
Is it good practice?
No, not in this shape.
You sometimes do Object Oriented Programming in C in a similar way (compare CPython's PyObject): You use one "base" object, and one "type" struct which have a structure like:
struct obj_type {
const char* name;
size_t length; // this is important so that you can copy the object later on without knowing its insides
};
struct obj_base {
obj_type* type;
};
Because it is guaranteed that in C, pointers to structs point to the address of their first element, you can use further objects that build atop of that:
struct more_complex_object {
obj_type* type;
int value;
};
...
int main() {
obj_type *more_complex_object_type = malloc(sizeof(obj_type));
more_complex_object_type->name = "A more complex object type";
more_complex_object_type->length = sizeof(more_complex_object);
more_complex_object *obj = malloc(more_complex_object_type->length);
obj->type = more_complex_object_type;
obj->value = 10;
...
//let's now use it as a simple instance of the "super" object
obj_base* just_an_object = (obj_base*)more_complex_object;
//when we copy things, we make sure to copy the full length:
obj_base* target = malloc(sizeof(more_complex_object));
memcpy(target, just_an_object, just_an_object->type->length);
//now, when handling an object, we can check its type
if(just_an_object->type == more_complex_object_type) {
more_complex_object *my_obj = (more_complex_object)just_an_object;
printf("value: %d\n", my_obj->value);
}
}
Yes it is safe, as long your compiler follows the C standard
Why doesn't GCC optimize structs?
But no, I do not consider this a good practice.
Good practices are relative, and should never be use as a rule. This construction is required if you want to simulate OO inheritance behavior with C.

pointer to a structure within a structure in C

I have a structure (let's call it structure1) which holds a pointer to another structure (structure2), this way.
typedef struct structure{
structure2 *pointer
}structure;
structure structVariable;
structVariable.pointer = functionThatReturnsAPointerToStructure2Variable();
The thing is, as the program changes context (for example, when calling functions), the return value of the following code changes
structVariable.pointer->someAttribute
Any idea of why this might be happening? If you need more info please ask. Thanks!
MORE INFO
This is the real-deal
structure would be this
typedef struct CPU{
int variableCounter;
int instructionPointer;
char *currentInstruction;
t_list *dataDictionary_list;
u_int32_t currentContext;
PCB *assignedPCB;
CPU_STATUS status;
}CPU;
And this is how I assign the pointer (PCB *pointer)
PCB *pcb_createFromScript(const char *script){
t_medatada_program *metadata = metadatada_desde_literal(script);
PCB *pcb = malloc(sizeof(PCB));
pcb->instructionCount = metadata->instrucciones_size;
pcb->tagCount = metadata->cantidad_de_etiquetas;
pcb->functionCount = metadata->cantidad_de_funciones;
int codeSegmentSize = strlen(script);
int tagIndexSize = 0;
if(metadata->etiquetas != 0){
tagIndexSize = strlen(metadata->etiquetas);
}
int instructionIndexSize = metadata->instrucciones_size * sizeof(t_intructions);
pcb_getSegments(pcb,1024,codeSegmentSize,tagIndexSize,instructionIndexSize);
pcb->currentContext = pcb->stackSegment;
pcb->variableCounter = 0;
memory_write(pcb->codeSegment,0,codeSegmentSize,script);
memory_write(pcb->tagIndexSegment,0,tagIndexSize,metadata->etiquetas);
memory_write(pcb->instructionIndexSegment,0,instructionIndexSize,(void *)metadata->instrucciones_serializado);
pcb->uniqueId = (int) random();
return pcb;
}
And then I assign it this way (myCPU is global), that's why I call it inside cpu_getPCB without passing it as a parameter
cpu_getPCB(*dummyPCB);
void cpu_getPCB(PCB myPCB){
myCPU.currentContext = myPCB.currentContext;
myCPU.assignedPCB = &myPCB;
}
Here is some speculation.
If you are modifying the object that structVariable.pointer points to in some function, then when you try to read structVariable.pointer->someAttribute, that value will change to reflect to modification to the object.
Another possibility, as the other answer mentioned, is that structVariable.pointer is pointing to local memory (stack memory for a function) which can easily be overwritten on a new function call. That can be corrected by using malloc to do heap allocation instead of stack allocation.
Here is the first and most obvious issue. You are taking the address of a parameter and assigning it to myCPU.assignedPCB.
Since C is pass-by-value, you have copied it instead of capturing the original. Moreover, the parameter has the same lifetime as a local variable, and will go away when the function returns.
void cpu_getPCB(PCB myPCB){
myCPU.currentContext = myPCB.currentContext;
myCPU.assignedPCB = &myPCB;
}
You can fix it by passing a pointer instead, since you are in C and do not have access to the reference type.
void cpu_getPCB(PCB* myPCB){
myCPU.currentContext = myPCB->currentContext;
myCPU.assignedPCB = myPCB;
}
The "structure2 *pointer" will be pointing at a piece of memory that will disappear when you change context. Allocate the Structure2 variable and free it when it's no longer needed

Why do we use pointers for objects instead of just the object value directly?

I'm confused why in this tutorial they use Node *next instead of just creating the struct like Node node. Why is this? The same with other objects like char *string.
I understand that pointers are variables that hold an address, so these are holding addresses whose value is a Node or a char, right? But why hold their address and not just write to them directly?
The following code is completely valid, right?
typedef struct {
int health;
} Boss;
Boss bigBoss;
bigBoss.health = 40;
Boss newBoss;
newBoss.health = 100;
bigBoss = newBoss;
Why is that not the traditional way to do things? What is the advantage of a pointer?
For updating memory
Your assignment copies content from a structure, but there are still two distinct structures:
#include<stdio.h>
typedef struct {
int health;
} Boss;
int main() {
Boss bigBoss;
bigBoss.health = 40;
Boss newBoss;
newBoss.health = 100;
bigBoss = newBoss;
bigBoss.health = 1;
newBoss.health = 2;
printf("%d %d\n", bigBoss.health, newBoss.health);
}
1 2
That copying behavior is the same that you get when you pass a structure to a function directly. If you pass a Boss to a function and try to modify it, you'll be modifying the copy that's local to that function, not the original Boss. If you pass a pointer to the Boss instead, then you can modify the contents of the original Boss. For instance:
#include<stdio.h>
typedef struct {
int health;
} Boss;
void fail_attack( Boss boss ) {
boss.health -= 10;
}
void succeed_attack( Boss *boss ) {
boss->health -= 10;
}
int main() {
Boss bigBoss;
bigBoss.health = 40;
fail_attack( bigBoss );
printf( "after fail_attack, health: %d\n", bigBoss.health );
succeed_attack( &bigBoss );
printf( "after succeed_attack, after succeed_attack, health: %d\n", bigBoss.health );
}
after fail_attack, health: 40
after succeed_attack, health: 30
To reduce the cost of parameter passing
Even when you don't need this modification behavior, passing a pointer still saves space because you don't have to copy the entire structure, but rather just a pointer. For a structure with just one integer field, this isn't a big difference, if a difference at all, but for structures with multiple fields, this is important.
For self referential types
A instance of a structure is really just a blob of memory populated by the fields declared in the structure. How big is the blob of memory? Well, it needs to be at least big enough to hold the fields, and possibly a bit bigger for memory alignment. Some data structures that hold references to other instances of the same data structure (e.g., linked lists and trees are some of the earliest encountered data structures). How big would a linked list node need to be to hold an element and a next node? Well, size(node) = size(element) + size(node). That clearly won't work. On the other hand, a pointer is a fixed size, so we can have a node that has an element and a pointer to another node.

C code passing struct into function Stack overflow

Okay so I'm having an issue with a current assignment (trust me this is a minuscule part of it) as we are required to write in C code and not C++, and we are not allowed to change certain parts of code. So I have a struct defined:
typedef struct someStruct {
int what;
int something[MAX];
int another[MAX];
} someType;
in main() I initialize all the values in a defined struct:
someType whatever, *whatptr;
EDIT:of course set the pointer to the struct, trying to simplify the code for the example It is present in my code already
whatptr = &whatever;
whatever.what = 0;
// initialize both arrays to hold 0 at all indexes
// Then I must call a function progRun()
progRun(); //I need to pass struct 'whatever' in some way
Now progRun() looks like this:
void progRun(){
printWhat(&whatever);
if (whatever.what == 0) {
//do stuff
}
}
I can't change anything inside this code except what parameters to pass inside the progRun() function and I can add stuff before printWhat(). I've tried changing progRun to
void progRun(someType *stptr)
then calling it in main as
progRun(whatptr);
but this causes a stack overflow issue for some reason, I've tried stepping through with a debugger and it only occurs when the function is called. Is there a better way to pass the 'whatever' struct to the function so it can be passed into progRun() and printWhat() and can access 'whatever.what'?
Any help would be greatly appreciated! in the meantime I'll try to figure it myself if I can.
EDIT: Something else must be wrong in the code even though everything else has compiled and ran perfectly fine until this code was added. If I can break down the code and find out what's wrong I'll update the question. And no I cannot post the whole code as it is an assignment (this isn't the goal of the assignment trust me it focuses on data forwarding and more, just need to get this basic thing working) Thank you for help everyone.
EDIT: the MAX number used in the struct for something[MAX] and another[MAX] was extremely large ( I left my desktop that I started this project with back home, I'm currently using an old laptop that can't handle large arrays). All the answers below, and some of the stuff I used before now works fine.
void progRun(someStruct *ptr) {
someStruct whatever2 = *ptr;
printWhat(whatever2);
if (whatever2.what == 0) { ...
}
whatptr = &whatever;
progRun(whatptr);
Your problem was that:
you need to pass a pointer to whatever, yet you were passing a variable (whatptr) that had absolutely nothing to do with whatever.
You need to first assign the pointer to whatever into your pointer variable.
You are not dereferencing the pointer in the function
Alternately, get rid of pointer variables:
void progRun(someType *stptr) {
printWhat(*stptr);
if (stptr->what == 0) { ...
}
progRun(&whatever);
Instruction
someType whatever, *whatptr;
is the problem:
*whatptr will not point to the struct whatever unless you do the assignment as follows:
whatptr = &whatever;
Alternatively you could dynamically allocate memory on the heap for a pointer to your struct whatever by using the malloc() function and pass the pointer returned by malloc to the function progrun:
whatptr = (someType*) malloc ( sizeof(someType) );
if (whatptr == NULL) exit (1);
//whatever you need to do with your code
progrun(whatptr); // call function like this
In this case of course you will need to dereference your pointer to access member elements of the struct by using the arrow -> operator:
whatpr->what = 0; // for example
Also, check these tutorials to understand both approaches:
link 1
link 2
If you can't change print and if statements then you should pass your function a copy of your struct:
void progRun( someType whatever ){ // <---Passing by copy
printWhat(&whatever);
if (whatever.what == 0) {
//do stuff
}
}
and in your main() you should just call the function like this:
someType whatever;
//assign values to members of the struct
progRun(whatever);
and do not need at all to define and assign a pointer to the struct.
Though passing variables to functions by copy (especially when they are objects composed by many variables such as a struct is) is not a good behaviour:
it will require an overhead to copy all member elements
your copy will have a limited scope, which means that any change you do to the variable inside of the function will be lost when your function ends and will not be reflected on variable at main scope

Resources