Please help me understand the warning generated in RefTest(). [-Wincompati - c

warning: returning 'struct example_str **' from a function with incompatible return type 'struct example_str *' [-Wincompatible-pointer-types]
return &(example1_str->member2[index]);
Please help understand why the warning is being generated. When example1_struct->member[index] is called, my understanding is it should return (struct example_struct*) Please help me understand the reason for warning. Thank you in advance.
#include <stdio.h>
#include "stdbool.h"
struct example_str{
int member1;
struct example_str* member2[5];
};
struct example_str* Reftest(int index);
void function2(int id, int* SigVal);
struct example_str* example1_str;
int main()
{
_Bool test;
int Val = (int) test;
function2(10,&Val);
return 0;
}
void function2(int id, int* SigVal){
struct example_str* ptr_to_str;
ptr_to_str = Reftest(1);
ptr_to_str -> member2[1] -> member1 = id;
printf("%d",ptr_to_str -> member2[1] -> member1);
}
struct example_str* Reftest(int index){
return &(example1_str->member2[index]);
}

struct example_str
{
int member1;
struct example_str* member2[5];
};
example_str has 2 members and
member1 is int
member2 is struct example_str*[5], a.k.a. an array of 5 pointers to struct example_str, from member2[0] to member2[4]. 5 pointers.
refTest returns struct example_str*, the same type of each member2
You can align the declarations to see better
struct example_str
{
int member1;
struct example_str* member2[5];
};
struct example_str* Reftest(int index);
So it is clear that whathever member2 is, it is the same that Reftest() returns.
So if you declare, as you did
struct example_str* Reftest(int index)
{
return &(example1_str->member2[index]);
}
As & is the operator address of, you are returning the address of member2[], that is itself a pointer --- struct example_str* --- and for sure its type is struct example_str**
The compilers says that
so0729.c:35:12: warning: returning 'struct example_str **' from a function
with incompatible return type
struct example_str *' [-Wincompatible-pointer-types]
35 | return &(example1_str->member2[index]);
| ^~~~~~~~~~~~~~
And it is what it is. Just take the & off.
Consider using typedef. It is usual and can lead to a code easier to read. And avoid global things declared outside main()
Example
This is a variation of your code using the pointers to pass references back and forth to the structs
#include <stdio.h>
typedef struct st_example_str
{
int member1;
struct st_example_str* member2[5];
} Example;
Example* Reftest(Example*, unsigned);
void function2(Example*, unsigned, int* SigVal);
int main()
{
Example A = {.member1 = 10};
Example B = {.member1 = 11};
Example C = {.member1 = 12};
Example D = {.member1 = 13};
Example E = {.member1 = 14};
Example ex1;
ex1.member1 = 1;
ex1.member2[0] = &A;
ex1.member2[1] = &B;
ex1.member2[2] = &C;
ex1.member2[3] = &D;
ex1.member2[4] = &E; // not used
C.member2[0] = &ex1; // cycle
D.member2[0] = &ex1; // cycle
E.member2[0] = &ex1; // cycle
char test = 42;
int Val = (int)test;
function2(&ex1, 2, &Val); // should set member1 of C to 42...
printf("ids (member1) pointed from the array inside ex1: ");
for (int i = 0; i < 5; i += 1)
printf("%d ", ex1.member2[i]->member1);
printf("\n");
printf("member1 for ex1: %d\n", ex1.member1);
return 0;
}
void function2(Example* E, unsigned id, int* SigVal)
{
// sets member1 of struct pointed by E->member[id] to
// the value pointed to by SigVal
Example* ptr_to_str = Reftest(E, id);
ptr_to_str->member2[0]->member1 = *SigVal;
}
Example* Reftest(Example* E, unsigned index)
{
return E->member2[index];
}
Example output
ids (member1) pointed from the array inside ex1: 10 11 12 13 14
member1 for ex1: 42
And you see that 42, the value of test, gets set in ex1 using a few references

Related

incompatible types when assigning to type struct * from struct

I can't understand why i get this error : The error is : "incompatible types when assigning to type 'PERSOANA * {aka struct *}' from type 'PERSOANA {aka struct }' "
Can you please explain me where is the mistake ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char name[20];
char name2[20];
char cnp[15];
} PERSON;
PERSON read_array(int n);
int main()
{
int n;
printf("n = ");
scanf("%d", &n);
PERSON *v;
v = read_array(n); //here i get the error
return 0;
}
PERSON read_array(int n) {
PERSON *v;
v = malloc(n * sizeof(PERSON));
for(int i = 0; i < n; i++) {
printf("name=");
gets(v[i].name);
//more instr
}
return v; // and also here
}
Return a pointer to PERSON, not the object PERSON.
// PERSON read_array(int n);
PERSON *read_array(int n);
// ^
// PERSON read_array(int n) {
// v
PERSON *read_array(int n) {
I can't understand why i get this error : Incompatible types when assigning to type PERSON from type PERSON.
I am reasonably confident that you do not get that error, but if you actually do then you should switch to a better compiler. I speculate that the error you get is instead
Incompatible types when assigning to type PERSON * from type PERSON
, because that's in fact what you are trying to do, given your declaration of function read_array().
From implementation and use, it appears that you want that function to return a pointer to a structure rather than a copy of the structure. That would be
PERSON *read_array(int n);
... and the same in the function definition.

Struct array typedef in struct shows incomplete data

I'm having trouble with a piece of code where a typedef array is created of a struct. That typedef is then used in another struct.
When receiving the typedef in a function and initialising the struct with the typedef in it, I only get data of the first element in the array.
Below I have a simplified example of what I'm getting at the moment.
struct simple_struct {
double a;
};
typedef struct simple_struct arr_typedef[2];
struct struct_with_typedef {
const arr_typedef typedef_arr;
};
void foo(const arr_typedef arg_s) {
struct struct_with_typedef test = {
*arg_s
};
int i;
for (i = 0; i < 2; i++) {
printf("value: %f \n", test.typedef_arr[i].a);
}
}
int main(int argc, char* argv[]) {
arr_typedef d_test = { {1}, {2} };
foo(d_test);
return 1;
}
When compiled, using gcc 4.4, and run I see the following output:
~/public > ./test
value: 1.000000
value: 0.000000
Would someone be able to explain why the value of the second item isn't available?
If I leave out the dereference I get the following error whilst compiling, which I also don't get:
test.c:82: error: incompatible types when initializing type 'double' using type 'const struct simple_struct *'
I have removed the typedef and the same result persists. Sort of understand that indeed that one initialiser value is given. But there is only one member in the struct, or are they expanded in the background?
If so, how would you initialise both values?
struct simple_struct {
double a;
};
struct struct_with_arr {
const struct simple_struct struct_arr[2];
};
void foo(const struct simple_struct arg_s[2]) {
struct struct_with_arr test = {{*arg_s}};
int i;
for (i = 0; i < 2; i++) {
printf("value: %f \n", test.struct_arr[i].a);
}
}
int main(int argc, char* argv[]) {
struct simple_struct d_test[2] = { {1}, {2} };
foo(d_test);
return 1;
}
In this declaration
struct struct_with_typedef test = {
*arg_s
};
there is used an object of the type struct simple_struct to initialize an array of the type const arr_typedef.
Firstly you need to enclose the initializer in braces and add an initializer for the second element of the array if you want to do so.
A correct way to initialize the array is the following
#include <stdio.h>
struct simple_struct
{
double a;
};
typedef struct simple_struct arr_typedef[2];
struct struct_with_typedef
{
const arr_typedef typedef_arr;
};
void foo( const arr_typedef arg_s )
{
struct struct_with_typedef test =
{
{ arg_s[0], arg_s[1] }
};
for ( int i = 0; i < 2; i++ )
{
printf("value: %f \n", test.typedef_arr[i].a);
}
}
int main( void )
{
arr_typedef d_test = { {1}, {2} };
foo(d_test);
return 0;
}
The program output is
value: 1.000000
value: 2.000000
You can write the initializers also the following way
struct struct_with_typedef test =
{
{ *arg_s, *( arg_s + 1 ) }
};
Take into account that an array designator used as an initializer expression is implicitly converted to pointer to its first element. Dereferencing the pointer you get the first element itself.
There is no syntax in C for initializing an array with a single initializer representing another array to copy values from.
To fix your code you could do one of these options:
List the members: struct struct_with_arr test = {{arg_s[0], arg_s[1]}};
Change the function to accept struct struct_with_arr as the parameter type, in which case you can use struct struct_with_arr test = arg;
Copy without an initializer: struct struct_with_arr test; memcpy(&test.struct_arr, arg_s, sizeof test.struct_arr);. (Actually you can't use this option since you have defined the struct element as const ... not really a great idea in the first place in my opinion)
For completeness I will mention the code:
struct struct_with_arr foo = *(struct struct_with_arr *)arg_s;
This is one of those things that is technically undefined behaviour (if the argument source was not actually a struct_with_arr) but is likely to work on any actual compiler that exists. My advice would be to not do this.

Why do My C Code go Wrong

The below is my code. Compiler generates the errors as
#include<stdio.h>
struct Shelf{
int clothes;
int *books;
};
struct Shelf b;
b.clothes=5;
*(b.books)=6;
Compiler generates the errors as below for both statements b.clothes=5; and b->books=6; in above code.
error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘->’ token
I'm not a beginner at C and I believe that what I have written is correct. Kindly solve my problem
FIRST
You cannot do this
struct Shelf{
int clothes;
int books;
};
struct Shelf b;
b.clothes=5;
b.books=6;
In global scope
You can assign value inside a function
int main (void )
{
b.clothes=5;
b.books=6;
}
Or initializing values on declaration
struct Shelf b = { .clothes = 5, .books = 6 };
Moreover as you can see b is not a pointer so using -> is not correct: use . to access members of struct.
SECOND
Your struct has a pointer member book
struct Shelf{
int clothes;
int *books;
};
What you can do is to set it to the address of another variable, like
int book = 6;
struct Shelf b = { .clothes = 5, .books = &book };
Or allocate memory for that pointer like
int main (void )
{
b.clothes=5;
b.books=malloc(sizeof(int));
if (b.books != NULL)
{
*(b.books) = 6;
}
}
BTW I guess you want an array of books, so
int main (void )
{
b.clothes=5;
b.books=malloc(sizeof(int) * MAX_N_OF_BOOKS);
if (b.books != NULL)
{
for (int i=0; i<MAX_N_OF_BOOKS; i++)
b.books[i] = 6;
}
}
COMPETE TEST CODE
#include <stdio.h>
#include <stdlib.h>
struct Shelf
{
int clothes;
int *books;
};
int main(void)
{
struct Shelf b;
b.clothes = 5;
b.books = malloc(sizeof(int));
if (b.books != NULL)
{
*(b.books) = 6;
}
printf ("clothes: %d\n", b.clothes);
printf ("book: %d\n", *(b.books) );
}
OUTPUT
clothes: 5
book: 6
b is a struct, not a pointer, so -> is not correct.
It's like doing (*b).books, which is wrong.
struct Shelf{
int clothes;
int *books;
};
One data member of the struct is a pointer, however:
struct Shelf b;
is not a pointer, it is just a struct as I said before.
As for your question in comment:
b.clothes=5;
is correct. Also something like this would be ok:
int number = 6;
b.books = &number;
-> operator used to access of member of struct via pointer. b is not dynamically allocated so b->books=6; is wrong. You should first allocate memory for member books and then dereference it.
b.books = malloc(sizeof(int));
*(b.books)= 6;

How can I do a structure type conversion like this?

say if I have two structure types:
typedef struct
{
unsigned int * a;
char * b;
char * c;
}TYPEA;
typedef struct
{
unsigned int * a;
unsigned int * b;
}TYPEB;
And I also have a pointer array, which contains pointer pointing to TYPEA types:
TYPEA* AArray[1] =
{
&ga,
};
ga is defined as:
TYPEA ga =
{
&num1,
&b,
&c,
};
If I have another TYPEA var defined, I can modify AArray[0]'s content's value, like this:
TYPEA another_ga =
{
&num3,
&b,
&c,
};
void change_AArray()
{
*AArray[0] = another_ga;
}
This works perfectly good, but the question is, as TYPEA and TYPEB's first 32bits are same(Both are unsigned int) is it possible for me to change AArray's ga's content to a TYPEB structure?
Here are my attempts:
void change_AArray()
{
/* *AArray[0] = another_ga; */
/* Compile Error */
/* *AArray[0] = gb; */
/* Compile Error */
/* *AArray[0] = (TYPEA)gb; */
/* Passed compile, but AArray[0] is not changed */
/* AArray[0] = (TYPEA*)&gb; */
}
I then tried to add another pointer and put it in AArray[0] instead of using &ga, but it can't pass compile stage, I think C is requiring a constant in the initialize list.
TYPEA * pga = &ga;
TYPEA* AArray[1] =
{
pga, // error, needs a constant expression.
};
void change_AArray()
{
AArray[0] = (TYPEA*)&gb;
}
Is it possible to do the type conversion?
The entire code:
#include <stdio.h>
typedef struct
{
unsigned int * a;
char * b;
char * c;
}TYPEA;
typedef struct
{
unsigned int * a;
unsigned int * b;
}TYPEB;
int num1 = 10, num2 = 20, num3 = 30;
char b = 'b', c = 'c';
TYPEA ga =
{
&num1,
&b,
&c,
};
TYPEA another_ga =
{
&num3,
&b,
&c,
};
TYPEB gb =
{
&num2,
&num3,
};
TYPEA* AArray[1] =
{
&ga,
};
void change_AArray()
{
*AArray[0] = another_ga;
/* How can I do this conversion? */
/* *AArray[0] = gb; */
}
int main(int argc, const char *argv[])
{
printf("ga.a: %d\n", *ga.a);
printf("gb.b: %d\n", *gb.a);
change_AArray();
printf("After calling change_AArray()\n");
printf("ga.a: %d\n", *ga.a);
printf("gb.b: %d\n", *gb.a);
return 0;
}
void change_AArray()
{
*AArray[0] = *((TYPEA*) &gb); //#1
/* error:
*(AArray[0]) = (TYPEA) gb; //#2
*/
}
You can use #1 for your purpose.
If use #2, gcc reports an error:
error: conversion to non-scalar type requested
Questions are:
- What's scalar/non-scalar type?
- What does this error message mean?
- Why #2 fails?
What's scalar/non-scalar type?
int, char, pointers are scalar type, and a structure is not.
See details here,http://herbert.the-little-red-haired-girl.org/en/prgmsc1/docs/part2a.pdf
What does this error message mean?
If you do assignment between scalar and non-scalar type, you'll get this error.
Why #2 fails?
For *(AArray[0]) = (TYPEA) gb;, both sides are non-scalar types. So, it looks like it shouldn't get the above error.
However, C doesn't allow cast between structures. See http://msdn.microsoft.com/en-us/library/d9f2bsy2.aspx.
A test program,
struct a{ int i;};
struct b{ int i; };
int main (int argc, char *argv[])
{
struct a aaa;
struct b bbb;
bbb = (struct b)aaa;
return 0;
}
gcc reports an error:
error: conversion to non-scalar type requested
So to conclude, the reason for failure of #2 is that C language doesn't allow cast between structures.
Well, you can use union
union UNION_AB {
TYPEA a;
TYPEB b;
};
UNION_AB* UARRAY[1] = { &ua };
You can't cast two different types of struct directly, you have to assign the fields like this:
(*AArray[0]).a = gb.a;

Initializing a Struct of a Struct

If I have a struct in C that has an integer and an array, how do I initialize the integer to 0 and the first element of the array to 0, if the struct is a member another struct so that for every instance of the other struct the integer and the array has those initialized values?
Initialisers can be nested for nested structs, e.g.
typedef struct {
int j;
} Foo;
typedef struct {
int i;
Foo f;
} Bar;
Bar b = { 0, { 0 } };
I hope this sample program helps....
#include <stdio.h>
typedef struct
{
int a;
int b[10];
}xx;
typedef struct
{
xx x1;
char b;
}yy;
int main()
{
yy zz = {{0, {1,2,3}}, 'A'};
printf("\n %d %d %d %c\n", zz.x1.a, zz.x1.b[0], zz.x1.b[1], zz.b);
return 0;
}
yy zz = {{0, {0}}, 'A'}; will initialize all the elements of array b[10] will be set to 0.
Like #unwind suggestion, In C all instances created should initialized manually. No constructor kind of mechanism here.
You can 0-initialize the whole struct with {0}.
For example:
typedef struct {
char myStr[5];
} Foo;
typedef struct {
Foo f;
} Bar;
Bar b = {0}; // this line initializes all members of b to 0, including all characters in myStr.
C doesn't have constructors, so unless you are using an initializer expression in every case, i.e. write something like
my_big_struct = { { 0, 0 } };
to initialize the inner structure, you're going to have to add a function and make sure it's called in all cases where the structure is "instantiated":
my_big_struct a;
init_inner_struct(&a.inner_struct);
Here is an alternative example how you would do things like this with object-oriented design. Please note that this example uses runtime initialization.
mystruct.h
#ifndef MYSTRUCT_H
#define MYSTRUCT_H
typedef struct mystruct_t mystruct_t; // "opaque" type
const mystruct_t* mystruct_construct (void);
void mystruct_print (const mystruct_t* my);
void mystruct_destruct (const mystruct_t* my);
#endif
mystruct.c
#include "mystruct.h"
#include <stdlib.h>
#include <stdio.h>
struct mystruct_t // implementation of opaque type
{
int x; // private variable
int y; // private variable
};
const mystruct_t* mystruct_construct (void)
{
mystruct_t* my = malloc(sizeof(mystruct_t));
if(my == NULL)
{
; // error handling needs to be implemented
}
my->x = 1;
my->y = 2;
return my;
}
void mystruct_print (const mystruct_t* my)
{
printf("%d %d\n", my->x, my->y);
}
void mystruct_destruct (const mystruct_t* my)
{
free( (void*)my );
}
main.c
int main (void)
{
const mystruct_t* x = mystruct_construct();
mystruct_print(x);
mystruct_destruct(x);
return 0;
}
You don't necessarily need to use malloc, you can use a private, statically allocated memory pool as well.

Resources