Different ways of referring to a structure member in C - c

I have used three different ways, which I think are equivalent, of assigning values to the members of the structures from another function. I am getting the result of b and c in the following structure correct but not that of a. Are these methods of changing the values of the member of the structure not equivalent?
#include<stdio.h>
typedef struct
{
int a,b,c;
}
test_str;
void change(test_str * my_str_ad);
int main()
{
test_str my_str;
change(&my_str);
printf("a: %d, b:%d, c: %d\n", my_str.a, my_str.b, my_str.c);
return 0;
}
void change(test_str * my_str_ad)
{
test_str my_str;
my_str = *my_str_ad;
my_str.a = 5;
(*my_str_ad).b = 6;
my_str_ad->c = 7;
}

my_str in main() is not same as my_str in change().
As you jump to change() the statement test_str my_str; create a new instance of test_str.
So member 'a' of my_str in main will not be effected by change().
(*my_str_ad).b = 6;
my_str_ad->c = 7; will work since you are modifying the test_str of main() using the pointer passed to change().

test_str my_str;
my_str = *my_str_ad;
my_str.a = 5;
What is happening here is that you are COPYING my_str_ad's target variable into my_str. So the changes you make to my_str do not affect the my_str in your main. This cannot be fixed in C. i.e only your other two methods can be used.
[C++ only]
What you can do to get this to work is to change the first line, as I mentioned, to-
test_str& my_str;

Related

How to add multiple values for a struct in c using pointer?

I don't know how to add multiple values for a struct in C using a pointer. Here's my code and the gcc error is:
error: assignment to expression with array type (p+0)->name = "Teszt";
#include <stdio.h>
typedef struct{
char name[101];
int born_in;
} paciens;
int main(){
paciens *p;
int n = 5;
p = (paciens*) malloc(n * sizeof(paciens));
(p+0)->name = "Test";
(p+0)->born_in = 1992;
printf("Name: %s ; Born in: %d\n", (p+0)->name, (p+0)->born_in);
return 0;
}
You cannot assign to an array, but you can assign to a struct, which contains an array:
p[0] = (paciens) { .name = "Test", .born_in = 1992};
will do this. This is called a compound literal.
https://ideone.com/f99rUF
Also note that you forgot to #include <stdlib.h> for malloc.
The member name is an array. You can't assign to an array, only copy to it. To copy a string use strcpy:
strcpy(p[0].name, "Test");
Any good book, tutorial or teacher should have mentioned this.

Copying Struct to a Pointer array in a function C

i have a huge problem allocating memory in C
i have this struct
typedef struct{
int x;
int y;
}T;
i want to create a function that dynamically adds a structs to a pointer.
something like:
int main()
{
T* t;
f(&t);
free(t);
}
up to this point i think everything is ok, now the function is where i get lost
void f(T** t)
{
T t1;
T t2;
T t3;
//first i malloc
*t=malloc(sizeof(T)*T_MAX_SIZE);//i want another function to make the array bigger, but this is not as important as the problem
t1.x=11;
t1.y=12;
t2.x=21;
t2.y=22;
t3.x=31;
t3.y=32;
//now i want to copy the values from t1,t2,t3 to t[0],t[1],t[2]
memcpy(&(*t[0]),&t1,sizeof(T));
memcpy(&(*t[1]),&t2,sizeof(T));
memcpy(&(*t[2]),&t3,sizeof(T));
}
i do not know the correct way of copying these structs.
the point of doing this is to use t out of the function
(in the main)
many thanks :D
Your memcpy calls are incorrect.
In the expression &(*t[0]), the array index has top precedence, followed by the pointer indirection. So with explicit parenthesis it looks like &(*(t[0])).
So it first tries to array subscript t, which is the address of t in main. In the case of t[0] it still works, but t[1] references something past that variable, invoking undefined behavior. You want the array index of what t points to, which is (*t)[i].
So the memcpy calls should be:
memcpy(&((*t)[0]),&t1,sizeof(T));
memcpy(&((*t)[1]),&t2,sizeof(T));
memcpy(&((*t)[2]),&t3,sizeof(T));
You don't need any copy functions to assign one structure to another - you simply equate them. So if you have
T var1 = {1, 2};
T var2 = var1;
the whole of var1 is copied to var2. Amending your (simplified) program:
#include <stdio.h>
#include <stdlib.h>
#define T_MAX_SIZE 10
typedef struct{
int x;
int y;
}T;
void f(T** t)
{
T t1;
*t=malloc(sizeof(T)*T_MAX_SIZE);
t1.x=11;
t1.y=12;
(*t)[0] = t1;
}
int main(void) {
T* t;
f(&t);
printf ("Result %d %d\n", t[0].x, t[0].y);
free(t);
return 0;
}
Program output:
Result 11 12

using #define for defining struct objects

I came across this simple program somewhere
#include<stdio.h>
#include<stdlib.h>
char buffer[2];
struct globals {
int value;
char type;
long tup;
};
#define G (*(struct globals*)&buffer)
int main ()
{
G.value = 233;
G.type = '*';
G.tup = 1234123;
printf("\nValue = %d\n",G.value);
printf("\ntype = %c\n",G.type);
printf("\ntup = %ld\n",G.tup);
return 0;
}
It's compiling (using gcc) and executing well and I get the following output:
Value = 233
type = *
tup = 1234123
I am not sure how the #define G statement is working.
How G is defined as an object of type struct globals ?
First, this code has undefined behavior, because it re-interprets a two-byte array as a much larger struct. Therefore, it is writing past the end of the allocated space. You could make your program valid by using the size of the struct to declare the buffer array, like this:
struct globals {
int value;
char type;
long tup;
};
char buffer[sizeof(struct globals)];
The #define is working in its usual way - by providing textual substitutions of the token G, as if you ran a search-and-replace in your favorite text editor. Preprocessor, the first stage of the C compiler, finds every entry G, and replaces it with (*(struct globals*)&buffer).
Once the preprocessor is done, the compiler sees this code:
int main ()
{
(*(struct globals*)&buffer).value = 233;
(*(struct globals*)&buffer).type = '*';
(*(struct globals*)&buffer).tup = 1234123;
printf("\nValue = %d\n",(*(struct globals*)&buffer).value);
printf("\ntype = %c\n",(*(struct globals*)&buffer).type);
printf("\ntup = %ld\n",(*(struct globals*)&buffer).tup);
return 0;
}
The macro simply casts the address of the 2-character buffer buf into a pointer to the appropriate structure type, then de-references that to produce a struct-typed lvalue. That's why the dot (.) struct-access operator works on G.
No idea why anyone would do this. I would think it much cleaner to convert to/from the character array when that is needed (which is "never" in the example code, but presumably it's used somewhere in the larger original code base), or use a union to get rid of the macro.
union {
struct {
int value;
/* ... */
} s;
char c[2];
} G;
G.s.value = 233; /* and so on */
is both cleaner and clearer. Note that the char array is too small.

Warning: X may be used uninitialized in this function

I am writing a custom "vector" struct. I do not understand why I'm getting a Warning: "one" may be used uninitialized here.
This is my vector.h file
#ifndef VECTOR_H
#define VECTOR_H
typedef struct Vector{
int a;
int b;
int c;
}Vector;
#endif /* VECTOR_ */
The warning happens here on line one->a = 12
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include "vector.h"
int main(void){
Vector* one;
one->a = 12;
one->b = 13;
one->c = -11;
}
one has not been assigned so points to an unpredictable location. You should either place it on the stack:
Vector one;
one.a = 12;
one.b = 13;
one.c = -11
or dynamically allocate memory for it:
Vector* one = malloc(sizeof(*one))
one->a = 12;
one->b = 13;
one->c = -11
free(one);
Note the use of free in this case. In general, you'll need exactly one call to free for each call made to malloc.
You get the warning because you did not assign a value to one, which is a pointer. This is undefined behavior.
You should declare it like this:
Vector* one = malloc(sizeof(Vector));
or like this:
Vector one;
in which case you need to replace -> operator with . like this:
one.a = 12;
one.b = 13;
one.c = -11;
Finally, in C99 and later you can use designated initializers:
Vector one = {
.a = 12
, .b = 13
, .c = -11
};
When you use Vector *one you are merely creating a pointer to the structure but there is no memory allocated to it.
Simply use one = (Vector *)malloc(sizeof(Vector)); to declare memory and instantiate it.
This might not be the most professional solution, but instead of initialising it using malloc, you can also initialise it using new:
Vector *one = new Vector();
I personally find it more elegant.

Re-typecasting a variable, possible?

Is it possible to recast the a variable permanently, or have a wrapper function such that the variable would behave like another type?
I would want to achieve something I posted in the other question:
Typecasting variable with another typedef
Update: Added GCC as compiler. May have a extension that would help?
Yes, you can cast a variable from one type to another:
int x = 5;
double y = (double) x; // <== this is what a cast looks like
However, you cannot modify the type of the identifier 'x' in-place, if that is what you are asking. Close to that, though, you can introduce another scope with that identifier redeclared with some new type:
int x = 5;
double y = (double) x;
{
double x = y; // NOTE: this isn't the same as the 'x' identifier above
// ...
}
// NOTE: the symbol 'x' reverts to its previous meaning here.
Another thing you could do, though it is really a horrible, horrible idea is:
int x = 5;
double new_version_of_x = (double) x; // Let's make 'x' mean this
#define x new_version_of_x
// The line above is pure evil, don't actually do it, but yes,
// all lines after this one will think 'x' has type double instead
// of int, because the text 'x' has been rewritten to refer to
// 'new_version_of_x'. This will likely lead to all sorts of havoc
You accomplish that by casting then assigning.
int f(void * p) {
int * i;
i = (int *)p;
//lots of code here with the i pointer, and every line
//really thinks that it is an int pointer and will treat it as such
}
EDIT From the other question you linked:
typedef struct {
unsigned char a;
unsigned char b;
unsigned char c;
} type_a;
typedef struct {
unsigned char e;
unsigned char f[2];
} type_b;
//initialize type a
type_a sample;
sample.a = 1;
sample.b = 2;
sample.c = 3;
Now sample is initialized, but you want to access it differently, you want to pretend that in fact that variable has another type, so you declare a pointer to the type you want to "disguise" sample as:
type_b * not_really_b;
not_really_b = (type_b*)&sample;
See, that is the whole magic.
not_really_b->e is equal 1
not_really_b->f[0] is equal 2
not_really_b->f[1] is equal 3
Does this answer your question?
The other answers are better (declare a variable of the type you want, and do an assignment). If that's not what you're asking for, you could use a macro:
long i;
#define i_as_int ((int)i)
printf( "i = %ld\n", i);
printf( "i = %d\n", i_as_int);
But wouldn't it be clearer to just say (int) i if that's what you mean?
As long as you realize in C pointers are nothing but addresses of memory
locations of certain types, you should have your answer. For example the
following program will print the name of the file
int main(int argc, char *argv[]) {
int *i;
i = (int *) argv[0];
printf("%s\n", argv[0]);
printf("%s\n", ((char *) i));
}

Resources