Pointer and Structure problems - c

I am suppose to be creating a memory map of this program for my class, but when I try to compile it, I get an error:
invalid operands to binary expression ('double *' and 'double *')
I am a student, please do not edit the code to print out memory locations, I need to write that myself.
main()
{
double testd;
int testi;
FILE *fpt;
struct frog {
double *x, y;
}frog;
struct frog turtle, *apple, tv[3];
testi = 2;
apple = &turtle;
apple->x = &testd
*(turtle).x = 7.3; //this is where im getting the error.
(*apple).y = 3.6;
turtle.y = 1.5;
for (testi = 0; testi < 3; testi++)
tv[testi].x = &(tv[(testi+1)%3].y);
*(tv[1].x) = 6.4;
}

You are missing the ; at the end of the previous line.
You are not wrong to dereference *(turtle).x instead of *(turtle.x). The . operator has higher precedence than the * operator, meaning those two statements are equivalent and you don't even need parentheses: you could just do *turtle.x.
Check out this site for precedence ordering.

You are missing the ; at end of the previous line.
The compiler then interprets the * at the beginning of the line as a multiplication symbol and complains because that doesn't work out so well.

You simply forgot ; after apple->x = &testd statement.
On a side note, in C you have to say struct before a structure, and main function is supposed to return an integer. You also need to include header files with declarations of data structures and functions that you are using (i.e. stdio.h). Not to mention that // comment style is C99, and C programmers don't really use it.. /* */ comments are awesome.

Related

Affecting a "static" struct in another struct in heap

So I solved my problem, wasn't that hard, but I'm wandering why the first version wasn't working.
So here, an example of my problem :
typedef struct a {
int i;
} A;
typedef struct b {
int i;
A a;
} B;
typedef B * PB;
PB create_B(int ia, int ib) {
PB b = malloc(sizeof(B));
b->i = ib;
b->a = {ia};
}
I get an error from the compiler saying :
"error: expected expression before ‘{’ token"
at line: b->a = {ia};
But i don't really get what is the problem.
I solved it casting the structure :
PB create_B(int ia, int ib) {
PB b = malloc(sizeof(B));
b->i = ib;
b->a = (A){ia};
}
But the types are well defined no ? I mean it's kind of obvious to me that {ia} is of type A since b->a is of type A aswell.
I am probably wrong on this last saying (compiler is probably right). So if you have an example where this situation isn't obvious and really need a cast, it would be really appreciated, or jut an explanation at least.
Thank you for your time.
Barioth
PS :
I could have done that too i guess
PB create_B(int ia, int ib) {
PB b = malloc(sizeof(B));
*b = (B){ib, {ia}};
}
But i still need a cast...
{ia} is not an expression in C and cannot be used in an expression statement.
{ia} is part of a syntax for definitions. In a definition, a list of initial values may be given in braces after an =. (And the braces may be omitted when initializing a scalar object.) This is a special syntax for initializing in a definition and is not an assignment like using = in an expression.
(A){ia} is an expression; it is a construct called a compound literal. After a type name in parentheses, initial values are given inside braces. This creates an object of the stated type. That object may then be used in an expression, such as as the right operand of an assignment.

array of pointers to array of pointers in C

I have an API which will take triple pointer as an input as below.
extern int myAPI(int ***myData);
Internally "myData" is treated as array of pointer to array of pointers.
So now in another function, i need to call this myAPI. But i am not able to build the array of pointer to array of pointers. Can you please someone help?
I tried similar to below snippet of code. But seen type mismatch compilation error.
int i[10];
int j[10];
int *k[10];
int *l[10];
int *(*m[])[2];
int a = 0;
for (a = 0; a < 10; a++) {
k[a] = &(i[a]);
l[a] = &(j[a]);
}
m[0] = k;
m[1] = l;
a = myAPI(m);
So you want an "array 10 of pointer to array of pointer 20 to int" (you have to specify the dimensions for all but functions arguments where you can omit the outermost dimension only).
That would be:
int *(*a[10])[20];
For such constructs, cdecl is very helpful. The line in quotes is the declaration for the tool.
Note this is what you asked for. Which is not necessarily what you really need. Often such complex constructs are a symptom of a severe design flaw. You might want to reconsider your program code.
Try changing the declaration of m to
int **m[2];

Pointer to array structure

I have a small program which when compiling throws me the following errors
error #2168: Operands of '+' have incompatible types 'struct agenda' and 'int'.
error #2113: Left operand of '.' has incompatible type 'int'.
error #2088: Lvalue required.
This is the code that I have done
#include <stdio.h>
struct agenda{
int order, cellular;
char name[30], last_name[30], street[30], city[30], mail[50];
}contact[10];
int main(void)
{
struct agenda *ptrcontact;
ptrcontact = &contact[0];
(*ptrcontact+3).order = 3;
printf("\n\n %d", (*ptrcontact).order);
return 0;
}
because it throws these errors and how to fix them?
You need to change
(*ptrcontact+3).order = 3;
to
ptrcontact[3].order = 3;
or, at least,
(*(ptrcontact+3)).order = 3;
or,
(ptrcontact + 3)->order = 3;
Otherwise, as per the precedence rule, * has higher precedence over +, causing the error.
Just to add to that, ptrcontact is a pointer ( to struct agenda) and can be used as an operand to + operator.
OTOH, *ptrcontact is of type struct agenda and cannot be used as an operand to + operator.
You are dereferencing the pointer which yields the struct and obviously you can't add anything to that. Dereference operator has the highest priority, you need to do it like this: (*(ptr + 3)).order or use the arrow instead of star dot: (ptr + 3) -> order
Your problem here is operations priority:
(*ptrcontact+3).order = 3;
This derefers ptrcontract and then tries to add number to dereferred structure. Which gives you exact situation you report.
My recommendations:
Either avoid address ariphmetics in such cases. Operate array indexes.
int baseIndex = 0;
contact[baseIndex + 3].order = 3;
Or if you really have to do so, hide address arithmetic from outside:
(pcontact + 3)->order = 3;
And finally learn C language operations priority or, to do it once (but some C people don't like C++), C++ operations priority
the error is in the lines
(*ptrcontact+3).order = 3; and printf("\n\n %d", (*ptrcontact).order);. In this instructions use -> instead of . the errors will be solved.

lvalue required error while compiling

I have a struct
typedef struct _scaffale {
int NumeroScaffale;
scaffali * succ;
copia** pos;
} scaffale;
in which I have an array of the struct copia. The error comes in the following code:
copia** temp;
temp=scaff->pos;
(temp+controllo)=nuovo->copie;
in the third row to be precise. The question is: why this line give me that error while in the following code in which I use the same construct it is perfectly allowed:
while(i<=MAXLIBRI){
if ((temp+i)!=NULL) {
i=i+1;
}
else break;
}
(temp+controllo) is an rvalue. By that I mean it's a computed value, not a location to put something. I'm guessing that what you really meant is *(temp+controllo) = nuovo->copie; instead, which would have assigned nuovo->copie into the location identified by temp+controllo.
For an analogy, if i is an int, you can say i = 3, but you can't say (i+1) = 3. I hope it's obvious why.
(temp+controllo) is a computed value, and doesn't follow the language rules for being a proper l-value which is a fancy way of saying "you can't put it on the left of an assignment operator".

Passing pointers of arrays in C

So I have some code that looks like this:
int a[10];
a = arrayGen(a,9);
and the arrayGen function looks like this:
int* arrayGen(int arrAddr[], int maxNum)
{
int counter=0;
while(arrAddr[counter] != '\0') {
arrAddr[counter] = gen(maxNum);
counter++;
}
return arrAddr;
}
Right now the compilier tells me "warning: passing argument 1 of ‘arrayGen’ makes integer from pointer without a cast"
My thinking is that I pass 'a', a pointer to a[0], then since the array is already created I can just fill in values for a[n] until I a[n] == '\0'. I think my error is that arrayGen is written to take in an array, not a pointer to one. If that's true I'm not sure how to proceed, do I write values to addresses until the contents of one address is '\0'?
The basic magic here is this identity in C:
*(a+i) == a[i]
Okay, now I'll make this be readable English.
Here's the issue: An array name isn't an lvalue; it can't be assigned to. So the line you have with
a = arrayGen(...)
is the problem. See this example:
int main() {
int a[10];
a = arrayGen(a,9);
return 0;
}
which gives the compilation error:
gcc -o foo foo.c
foo.c: In function 'main':
foo.c:21: error: incompatible types in assignment
Compilation exited abnormally with code 1 at Sun Feb 1 20:05:37
You need to have a pointer, which is an lvalue, to which to assign the results.
This code, for example:
int main() {
int a[10];
int * ip;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
return 0;
}
compiles fine:
gcc -o foo foo.c
Compilation finished at Sun Feb 1 20:09:28
Note that because of the identity at top, you can treat ip as an array if you like, as in this code:
int main() {
int a[10];
int * ip;
int ix ;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
for(ix=0; ix < 9; ix++)
ip[ix] = 42 ;
return 0;
}
Full example code
Just for completeness here's my full example:
int gen(int max){
return 42;
}
int* arrayGen(int arrAddr[], int maxNum)
{
int counter=0;
while(arrAddr[counter] != '\0') {
arrAddr[counter] = gen(maxNum);
counter++;
}
return arrAddr;
}
int main() {
int a[10];
int * ip;
int ix ;
/* a = arrayGen(a,9); */
ip = a ; /* or &a[0] */
ip = arrayGen(ip,9);
for(ix=0; ix < 9; ix++)
ip[ix] = 42 ;
return 0;
}
Why even return arrAddr? Your passing a[10] by reference so the contents of the array will be modified. Unless you need another reference to the array then charlies suggestion is correct.
Hmm, I know your question's been answered, but something else about the code is bugging me. Why are you using the test against '\0' to determine the end of the array? I'm pretty sure that only works with C strings. The code does indeed compile after the fix suggested, but if you loop through your array, I'm curious to see if you're getting the correct values.
I'm not sure what you are trying to do but the assignment of a pointer value to an array is what's bothering the compiler as mentioned by Charlie. I'm curious about checking against the NUL character constant '\0'. Your sample array is uninitialized memory so the comparison in arrayGen isn't going to do what you want it to do.
The parameter list that you are using ends up being identical to:
int* arrayGen(int *arrAddr, int maxNum)
for most purposes. The actual statement in the standard is:
A declaration of a parameter as "array of type" shall be adjusted to "qualified pointer to type", where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
If you really want to force the caller to use an array, then use the following syntax:
void accepts_pointer_to_array (int (*ary)[10]) {
int i;
for (i=0; i<10; ++i) {
(*ary)[i] = 0; /* note the funky syntax is necessary */
}
}
void some_caller (void) {
int ary1[10];
int ary2[20];
int *ptr = &ary1[0];
accepts_pointer_to_array(&ary1); /* passing address is necessary */
accepts_pointer_to_array(&ary2); /* fails */
accepts_pointer_to_array(ptr); /* also fails */
}
Your compiler should complain if you call it with anything that isn't a pointer to an array of 10 integers. I can honestly say though that I have never seen this one anywhere outside of various books (The C Book, Expert C Programming)... at least not in C programming. In C++, however, I have had reason to use this syntax in exactly one case:
template <typename T, std::size_t N>
std::size_t array_size (T (&ary)[N]) {
return N;
}
Your mileage may vary though. If you really want to dig into stuff like this, I can't recommend Expert C Programming highly enough. You can also find The C Book online at gbdirect.
Try calling your parameter int* arrAddr, not int arrAddr[]. Although when I think about it, the parameters for the main method are similar yet that works. So not sure about the explanation part.
Edit: Hm all the resources I can find on the internet say it should work. I'm not sure, I've always passed arrays as pointers myself so never had this snag before, so I'm very interested in the solution.
The way your using it arrayGen() doesn't need to return a value. You also need to place '\0' in the last element, it isn't done automatically, or pass the index of the last element to fill.
#jeffD
Passing the index would be the preferred way, as there's no guarantee you won't hit other '\0's before your final one (I certainly was when I tested it).

Resources