I am trying to work on an assignment with Struct nodes and linked lists. Here is a small part of the code where I am getting an error that I am unable to resolve. Please help Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
struct term{
char term[200];
double value;
};
void main(){
struct term **terms = (struct term *)malloc(sizeof(struct term));
// Using **terms is mandatory for the project
*terms[0]->term = "abc";
*terms[0]->value = 1; //This is line 15
//I am unable to fix the error in line 15 at "*terms".
//The error message states "Struct term **terms: Operend of '*' must be a pointer"
//The goal is to create nodes that can be accessed using *terms[i] with a for loop of index i
}
The variable "terms" is a ** (pointer to pointer), but you're dereferencing it three times: once with *, once with [], and once with ->. You probably mean "terms[0]->term".
There are a few problems with this implementation. First of all, you are creating a double pointer so you also need to allocate memory for the inner-pointer you are pointing to.
struct term** terms = (struct term**)malloc(sizeof(struct term*));
*terms = (struct term*)malloc(sizeof(struct term));
Secondly, you cannot do an implementation like shown below.
char c[5];
void main(void)
{
c = "abc";
}
This is wrong and compiler will throw an error. What you can do is to assign each character to the char array one-by-one. Alternatively you can use strcpy too.
((*terms)->term)[0] = 'a';
((*terms)->term)[1] = 'b';
((*terms)->term)[2] = 'c';
Given this ...
struct term **terms = (struct term *)malloc(sizeof(struct term));
... terms represents an object of type struct term **, a pointer to a pointer to a struct term. In that case,
*terms[0]->term is equivalent to *((terms[0])->term) by operator precedence
terms[0] is equivalent to *terms. It is a pointer of type struct term *.
terms[0]->term designates the member term of the structure to which terms[0] points, which is an array. This array value is automatically converted to a pointer to the first array element for the purposes of evaluating the larger expression.
*terms[0]->term therefore represents the first character in the array terms[0]->term. It is equivalent to terms[0]->term[0]. It does not make sense to attempt to assign a string literal to this one character.
Similarly, terms[0]->value designates member value of the structure to which terms[0] points. This is not a pointer, so it is not a suitable operand for the * operator. This is what your compiler's error message is telling you.
Syntactically, any of these would be consistent with the type of terms:
terms[0]->value = 1;
(*terms[0]).value = 1;
(*terms)->value = 1;
HOWEVER, even if one of those were used, the code would still be badly broken. I already mentioned the bad assignment to *terms[0].term. Also, the malloc() call reserves the wrong amount of memory for terms to point to, albeit probably more than enough for a single struct term *. Most problematically, however, terms[0] itself, the pointer, is never initialized with a valid (pointer) value. It doesn't point to anything to whose members you could actually assign. Probably, then, you want something more like this:
struct term **terms = malloc(sizeof(*terms)); // enough space for one pointer
*terms = malloc(sizeof **terms)); // enough space for one struct term
strcpy(terms[0]->term, "abc");
terms[0]->value = 1;
// ...
Plus, the return type of main() must be int, not void.
Related
I have only been learning C for less than a week (with my knowledge of C++ and other languages to help) and I am confused on pointers and their ways of being declared.
Below, I use a simple struct named Object:
struct Object { int id; };
Do the below methods for creating a pointer do the same thing just in a different way, or no?
struct Object obj1 = { .id = 1 };
struct Object* obj1_p = &obj1; // method 1 of getting a pointer
// The same, just in a compound literal?
struct Object* obj2_p = &(struct Object){ .id = 1 }; // method 2 of getting a pointer
// Is this the same, other than being uninitialized?
struct Object* obj3_p = malloc(sizeof(struct Object)); // method 2 of getting a pointer
Is there a time when you only can use one method?
Also, as a side note, why do some people cast malloc, and is it better to do it?
// malloc is casted to object:
struct Object* obj3_p = (Object*)malloc(sizeof(struct Object));
These two “methods” do exactly the same thing. And as you said, the second one is just a compound literal.
struct Object obj1 = { .id = 1 };
struct Object *obj1_p = &obj1;
// The same, just in a compound literal?
struct Object *obj2_p = &(struct Object){ .id = 1 };
This allocates enough memory for struct Object without initializing it. And no you don't need to cast it, because malloc returns void *, which is automatically and safely promoted to any other pointer. But if you do, you should cast it to struct Object* instead of Object*.
struct Object *obj3_p = (struct Object*) malloc(sizeof(struct Object));
That looks very bulky though... My preferred way of doing it is this:
struct Object *obj3_p = malloc(sizeof *obj3_p);
I wrote this piece of code, hope it helps you to better understand some features of pointers:
#include <stdio.h>
#include <stdlib.h>
struct Object { int id; };
struct Object *getObjectBold() {
struct Object* obj2_p = &(struct Object) { .id = 2 };
return obj2_p; // UB: Returns the address of a local object (the compound literal).
}
struct Object *getObject() {
struct Object* obj3_p = malloc(sizeof(*obj3_p)); // Better way of calling malloc than using sizeof(struct Object).
obj3_p->id = 3; // You don't need to do this.
return obj3_p; // This needs to be freed later on!
}
int main(void) {
struct Object obj1 = { .id = 1 };
struct Object* obj1_p = &obj1;
printf("obj1.id = %d\n", obj1_p->id);
obj1_p->id = 10; // You can change values using the pointer
printf("obj1.id = %d\n", obj1_p->id);
// The only different thing with this case is that you don't
// "lose" your object when setting the pointer to NULL
// (although you can only access it through the object, not through the pointer).
obj1_p = NULL;
printf("obj1.id = %d\n", obj1_p->id); // This won't work (undefined behaviour).
printf("obj1.id = %d\n", obj1.id); // This will.
struct Object* obj2_p = &(struct Object) { .id = 1 };
obj2_p->id = 2; // You can change the id
printf("obj2.id = %d\n", obj2_p->id);
// If you make this pointer point to another address, you "lose" your object.
obj2_p = NULL;
printf("obj2.id = %d", obj2_p->id); // This won't work at all (undefined behaviour).
// Both of these pointers point to objects in the stack, so, for example,
// they don't work when returning from a function.
obj2_p = getObjectBold();
obj2_p->id = 20; // This won't work (undefined behaviour).
printf("obj2.id = %d\n", obj2_p->id); // This works if you don't dereference the pointer.
// The third case is not the same as the other two, since you are allocating memory on the heap.
// THIS is a time where you can only use one of these three methods.
struct Object *obj3_p = getObject(); // This works!
printf("obj3.id = %d\n", obj3_p->id);
obj3_p->id = 30; // This works now.
printf("obj3.id = %d\n", obj3_p->id);
free(obj3_p); // You need to do this if you don't want memory leaks.
return 0;
}
This is the output when commenting out undefined behaviour:
obj1.id = 1
obj1.id = 10
obj1.id = 10
obj2.id = 2
obj2.id = 2
obj3.id = 3
obj3.id = 30
I'd recommend you to check out these links, they turned out to be pretty helpful for me:
Returning a pointer from a function
What and where are the stack and heap?
What EXACTLY is meant by “de-referencing a NULL pointer”?
Why dereferencing a null pointer is undefined behaviour?
Do I cast the result of malloc?
There are two distinct topics in your question.
struct Object* obj1_p = .......;
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^
pointer object initialization
definition
Pointer variable definition
You can define the pointer variable only one way:
type *objectname;
Initialization assigns the value to the pointer variable. This value should reference the valid object of the same type as the pointer or valid memory of the size not smaller than the pointer type. The difference in your examples is how the referenced object is created.
Is there a time when you only can use one method?
That only depends on the program logic. You only must remember about the scope of the underlying object to avoid dereferencing objects which does not exist outside the particular scope:
struct Object *valid1(void) //valid
{
struct Object* obj3_p = malloc(sizeof(*obj3_p));
return obj3_p;
}
struct Object obj1 = { .id = 1 };
struct Object *valid2(void) // valid
{
struct Object* obj3_p = &obj1;
return obj3_p;
}
struct Object *invalid1(void) // invalid
{
struct Object obj1 = { .id = 1 };
struct Object* obj3_p = &obj1;
return obj3_p;
}
struct Object *invalid2(void) // invalid
{
struct Object* obj3_p = &(struct Object){ .id = 1 };
return obj3_p;
}
Also, as a side note, why do some people cast malloc, and is it better
to do it?
It is considered as bad practice as it silences the warning if there is no prototype of the malloc. Better do not cast. Modern compilers and recent C standard disallow the use of the functions without prototypes
It is better to use sizeof(object) instead of sizeof(type) as if you change the type of the object you need to change oll of the occurrences of the sizeof(type) in your program. It very easy to miss some and get very hard to discover errors.
First, let's straighten out some terminology -
You are declaring all three pointers the exact same way:struct Object* objn_p ...
The only difference is in how you are initializing them.
Declarations in C have two major components - a sequence of declaration specifiers followed by a comma-separated list of optionally initialized declarators. C++ declarations are structured fundamentally the same way, but for this answer I will stick with C terminology (since that's the language we're talking about the one I'm more familiar with).
Declaration specifiers include storage class specifiers (auto, static, register, typedef, etc.), type specifiers (int, char, double, short, etc.), type qualifiers (const, volatile, restrict), and a few others.
Declarators include the name of the thing being declared, along with information about its pointer-ness, array-ness, and/or function-ness.
Initializers for scalar objects are scalars. Initializers for aggregate objects like arrays, structs, and unions are brace-enclosed lists or, in the case of character arrays, a string literal.
In the declaration
struct Object* obj1_p = &obj_1;
the declaration specifier is struct Object, the declarator is * obj1_p, and the initializer is = &obj_1.
I know the C++ convention for declaring pointer objects is T* p, but the syntax is actually T (*p) - the * operator is always bound to the declarator, not the type specifier. If you write T* p, q; then only p is declared as a pointer to T; q is declared as an instance of T. I know why the C++ convention exists, I know the justifications for it, but it does misrepresent how declaration syntax works in both C and C++ and I consider it a mistake to use. Most C programmers will use the T *p convention instead1.
Here are the basic rules for pointer declarations in C:
Declaration Declarator
Specifier
----------- ----------
T *p; // p is a pointer to T
T *a[N]; // a is an array of pointer to T
T *f(); // f is a function returning a pointer to T
T (*a)[N]; // a is a pointer to an array of T
T (*f)(); // f is a pointer to a function returning T
The rules for const are:
T const *p; // p points to a const T
const T *p; // same as above
T * const p; // p is a const pointer to T
What differs between your three methods is how you initialize the pointer.
Method 1 is just taking the address of a previously-declared variable of the same type:
struct Object *obj1_p = &obj1; // using the C convention for pointer declarations
Method 2 is taking the address of a compound literal - basically, an anonymous variable:
struct Object *obj2_p = &(struct Object){ .id = 1 };
The only difference between obj1 and the anonymous object is that you can refer to obj1 directly as well as through the pointer:
printf( "%d %d %d", obj1.id, obj1_p->id, (*obj1_p).id );
whereas you can only refer to the anonymous object through the pointer variable
printf( "%d %d", obj2_p->id, (*obj2_p).id );
Method 3 dynamically allocates memory and assigns the address of the resulting object (which may be NULL if the malloc call fails).
struct Object *obj3_p = malloc( sizeof( struct Object ) );
The chief difference between this and the other two methods is that the memory allocated by malloc hangs around until you explicitly free it, whether the obj3_p variable goes out of scope or not. If obj1 and the anonymous object are declared within a block and without the static keyword, then that memory is automatically released when the block containing them exits.
Also, as a side note, why do some people cast malloc, and is it better to do it?
There are two times when you must cast the result of malloc (and calloc and realloc):
You are compiling the code as C++;
You are working with an ancient, pre-C89 K&R implementation.
Unlike C, C++ does not allow implicit conversion between void * (the type returned from malloc) and other pointer types. You must explicitly cast conversions to or from void *. Having said that, if you're writing C++ you should not be calling malloc directly. You should either be using a container that manages memory for you under the hood (std::string, std::vector, std::map, etc.) or you should be using the new or new [] operators. If you're in the middle of a lift-and-shift from C to C++, it's acceptable to keep the malloc calls until you can get around to rewriting your memory management code, but ideally C++ code should never use malloc (or calloc or realloc) directly.
In the earliest versions of C, malloc, calloc, and realloc returned char *, so you had to cast the result if you were assigning it to pointers of different types:
int *p = (int *) malloc( sizeof *p * N );
As someone who wrote K&R C in college, this was a pain in the ass. It was cluttered and a constant source of mistakes. If you changed the type of p (say from int * to long *) you had to repeat that change in multiple places. That created a higher maintenance burden, especially if (as was often the case) the pointer declaration was separated from the malloc call by other code:
int *p = NULL;
...
p = (int *) malloc( sizeof *p * N );
Prior to C99, you had to declare all variables before any statements (in that block, anyway), so it was common for pointer declarations to be separated from the malloc call by multiple lines of code. It was really easy to change the type of *p in the declaration but forget to do it in the assignment later, causing subtle (and sometimes not-so-subtle) runtime errors.
The 1989 standard introduced the void type and changed the *alloc functions to return void *. It also introduced the rule that you could assign void * values to other pointer types and vice versa without an explicit cast. So you could write a malloc call as:
int *p = malloc( sizeof *p * N );
or
int *p = NULL;
...
p = malloc( sizeof *p * N );
If you change the type of *p, you only have to make that change in one place. It's cleaner, it's harder to screw up, etc.
Also, under the C89 standard, casting the result of malloc could suppress a useful compiler diagnostic if you forgot to include stdlib.h or otherwise didn't have a declaration for malloc in scope. But since C99 did away with implicit int declarations2, that's not really an issue anymore.
However, there are people who prefer to keep the explicit cast for various reasons. Personally, I have found those reasons wanting, and I've accumulated enough scar tissue from bad casts that I prefer to leave them off entirely. 30+ years of writing code has convinced me that when it comes to memory management, simpler is always better. It doesn't hurt to use them; they don't slow down the code or anything like that. But from a readability and maintenance standpoint, casting malloc is bad juju.
Whitespace in declarations is only significant in that it separates tokens. The * character is a token on its own and not part of any identifier, so you can write any of T *p, T* p, T*p, or T * p and they will all be parsed as T (*p).
Prior to C99, if the compiler saw a function call without a preceding declaration, it assumed the function returned int, so if you forgot to include stdlib.h the compiler would complain if you tried to assign the result of malloc to a pointer since an int can't be implicitly converted to a pointer. However, if you used the cast, then the diagnostic would be suppressed.
I'm studying searching procedures in lists (C language), and I've seen procedures use both the arrow operator and the dot operator when writing conditions.
For a struct like...
struct node{
int value; //value, can be any type
struct node *next;
};
I've seen...
if(current->next->value == searched_value)
...and
if(current->next.value == searched_value)
...being used. My question is: Are are these method interchangeable in any given case? (i.e they are the same)
As #PabloSantaCruz correctly notes, accessing members of a struct using '->' and '.' are very much not the same.
To know which to use, you simply have to answer the question of "Do I have a struct or pointer to struct?"
When accessing struct members, the '->' (arrow) operator is used to dereference a pointer to struct to access the members. When dealing with a struct itself the '.' (dot) operator is used to access its members.
There is nothing better than practice and an example to help compare/contrast the usage, for example, the following declares an array of struct to serve as your list, where each element is a struct. To simply access the members of each element all that is needed is the dot operator. However, to show how they are related, if you take the address of each element, thereby creating a pointer to it, the arrow operator can be used.
#include <stdio.h>
struct node {
int val;
struct node *next;
};
int main (void) {
struct node list[2] = {{1, &list[1]}, {2, NULL}}, /* array */
*l = list; /* pointer to first element */
puts ("\nusing list, e.g. list[0].val\n"); /* the dot operator */
printf (" %d %d\n", list[0].val, list[1].val);
/* taking the address of each element and using the arrow operator */
puts ("\nusing address of each list element, e.g. (&list[0])->val\n");
printf (" %d %d\n", (&list[0])->val, (&list[1])->val);
puts ("\nusing l, e.g. l->val\n"); /* using the pointer & arrow op. */
printf (" %d %d\n", l->val, (l + 1)->val);
puts ("\ntraversing list using l\n"); /* traversing with the pointer */
while (l) {
printf (" %d", l->val);
l = l->next;
}
putchar ('\n');
}
In each case above, you simply answer the question "Do I have a struct or pointer to struct?" to know which operator to use.
Example Use/Output
$ ./bin/ll_array
using list, e.g. list[0].val
1 2
using address of each list element, e.g. (&list[0])->val
1 2
using l, e.g. l->val
1 2
traversing list using l
1 2
Look things over and let me know if you have further questions.
No. They're definitely not the same and they are not interchangeable.
The arrow operator -> only works when you have a pointer to a struct as a variable.
So:
struct *p;
p->a = 0; // correct
p.a = 0; //syntax error
Clearly you must have been looking something else, because if next is of struct node * type (a pointer to struct node) then, current->next.value is an error.
In gcc you should get an error saying: error: request for member ‘value’ in something not a structure or union
current->next->value can also be written (*(*current).next).value).
The reason you need those parenthesis is that . has higher precedence than *. The -> is basically just syntactic sugar to reduce the amount of parenthesis.
Are are these method interchangeable in any given case?
In a way yes. You can always use dots instead of arrows if you use parenthesis the proper way. You can also go the other way. This code compiles without warnings and prints 1 2 3 4.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int foo;
int bar;
} myStruct;
int main() {
myStruct a;
(&a)->foo = 1;
a.bar = 2;
myStruct * b = malloc(sizeof *b);
b->foo = 3;
(*b).bar = 4;
printf("%d %d %d %d\n", a.foo, (&a)->bar, (*b).foo, b->bar);
}
The -> operator requires the left operator to be a pointer, while . requires it to not be a pointer. But as you can see, dereferencering a pointer (using *) gives you the data the pointer is pointing at, and thus you can use . instead. And using & gives you the address of the object, which enforces the use of -> instead of ..
In practice, this should never be an issue. Choose the most convenient, and I cannot think of an example where I would not know which to choose.
Actually, this is related to the [] operator, which you are using for indexing arrays. That is also just syntactic sugar. The expression a[i] is equivalent to *(a+i). This has the funny consequence that a[i] is actually the same as i[a].
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.
I am reading a book called "Teach Yourself C in 21 Days" (I have already learned Java and C# so I am moving at a much faster pace). I was reading the chapter on pointers and the -> (arrow) operator came up without explanation. I think that it is used to call members and functions (like the equivalent of the . (dot) operator, but for pointers instead of members). But I am not entirely sure.
Could I please get an explanation and a code sample?
foo->bar is equivalent to (*foo).bar, i.e. it gets the member called bar from the struct that foo points to.
Yes, that's it.
It's just the dot version when you want to access elements of a struct/class that is a pointer instead of a reference.
struct foo
{
int x;
float y;
};
struct foo var;
struct foo* pvar;
pvar = malloc(sizeof(struct foo));
var.x = 5;
(&var)->y = 14.3;
pvar->y = 22.4;
(*pvar).x = 6;
That's it!
I'd just add to the answers the "why?".
. is standard member access operator that has a higher precedence than * pointer operator.
When you are trying to access a struct's internals and you wrote it as *foo.bar then the compiler would think to want a 'bar' element of 'foo' (which is an address in memory) and obviously that mere address does not have any members.
Thus you need to ask the compiler to first dereference whith (*foo) and then access the member element: (*foo).bar, which is a bit clumsy to write so the good folks have come up with a shorthand version: foo->bar which is sort of member access by pointer operator.
a->b is just short for (*a).b in every way (same for functions: a->b() is short for (*a).b()).
foo->bar is only shorthand for (*foo).bar. That's all there is to it.
Well I have to add something as well. Structure is a bit different than array because array is a pointer and structure is not. So be careful!
Lets say I write this useless piece of code:
#include <stdio.h>
typedef struct{
int km;
int kph;
int kg;
} car;
int main(void){
car audi = {12000, 230, 760};
car *ptr = &audi;
}
Here pointer ptr points to the address (!) of the structure variable audi but beside address structure also has a chunk of data (!)! The first member of the chunk of data has the same address than structure itself and you can get it's data by only dereferencing a pointer like this *ptr (no braces).
But If you want to acess any other member than the first one, you have to add a designator like .km, .kph, .kg which are nothing more than offsets to the base address of the chunk of data...
But because of the preceedence you can't write *ptr.kg as access operator . is evaluated before dereference operator * and you would get *(ptr.kg) which is not possible as pointer has no members! And compiler knows this and will therefore issue an error e.g.:
error: ‘ptr’ is a pointer; did you mean to use ‘->’?
printf("%d\n", *ptr.km);
Instead you use this (*ptr).kg and you force compiler to 1st dereference the pointer and enable acess to the chunk of data and 2nd you add an offset (designator) to choose the member.
Check this image I made:
But if you would have nested members this syntax would become unreadable and therefore -> was introduced. I think readability is the only justifiable reason for using it as this ptr->kg is much easier to write than (*ptr).kg.
Now let us write this differently so that you see the connection more clearly. (*ptr).kg ⟹ (*&audi).kg ⟹ audi.kg. Here I first used the fact that ptr is an "address of audi" i.e. &audi and fact that "reference" & and "dereference" * operators cancel eachother out.
struct Node {
int i;
int j;
};
struct Node a, *p = &a;
Here the to access the values of i and j we can use the variable a and the pointer p as follows: a.i, (*p).i and p->i are all the same.
Here . is a "Direct Selector" and -> is an "Indirect Selector".
I had to make a small change to Jack's program to get it to run. After declaring the struct pointer pvar, point it to the address of var. I found this solution on page 242 of Stephen Kochan's Programming in C.
#include <stdio.h>
int main()
{
struct foo
{
int x;
float y;
};
struct foo var;
struct foo* pvar;
pvar = &var;
var.x = 5;
(&var)->y = 14.3;
printf("%i - %.02f\n", var.x, (&var)->y);
pvar->x = 6;
pvar->y = 22.4;
printf("%i - %.02f\n", pvar->x, pvar->y);
return 0;
}
Run this in vim with the following command:
:!gcc -o var var.c && ./var
Will output:
5 - 14.30
6 - 22.40
#include<stdio.h>
int main()
{
struct foo
{
int x;
float y;
} var1;
struct foo var;
struct foo* pvar;
pvar = &var1;
/* if pvar = &var; it directly
takes values stored in var, and if give
new > values like pvar->x = 6; pvar->y = 22.4;
it modifies the values of var
object..so better to give new reference. */
var.x = 5;
(&var)->y = 14.3;
printf("%i - %.02f\n", var.x, (&var)->y);
pvar->x = 6;
pvar->y = 22.4;
printf("%i - %.02f\n", pvar->x, pvar->y);
return 0;
}
The -> operator makes the code more readable than the * operator in some situations.
Such as: (quoted from the EDK II project)
typedef
EFI_STATUS
(EFIAPI *EFI_BLOCK_READ)(
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
);
struct _EFI_BLOCK_IO_PROTOCOL {
///
/// The revision to which the block IO interface adheres. All future
/// revisions must be backwards compatible. If a future version is not
/// back wards compatible, it is not the same GUID.
///
UINT64 Revision;
///
/// Pointer to the EFI_BLOCK_IO_MEDIA data for this device.
///
EFI_BLOCK_IO_MEDIA *Media;
EFI_BLOCK_RESET Reset;
EFI_BLOCK_READ ReadBlocks;
EFI_BLOCK_WRITE WriteBlocks;
EFI_BLOCK_FLUSH FlushBlocks;
};
The _EFI_BLOCK_IO_PROTOCOL struct contains 4 function pointer members.
Suppose you have a variable struct _EFI_BLOCK_IO_PROTOCOL * pStruct, and you want to use the good old * operator to call it's member function pointer. You will end up with code like this:
(*pStruct).ReadBlocks(...arguments...)
But with the -> operator, you can write like this:
pStruct->ReadBlocks(...arguments...).
Which looks better?
#include<stdio.h>
struct examp{
int number;
};
struct examp a,*b=&a;`enter code here`
main()
{
a.number=5;
/* a.number,b->number,(*b).number produces same output. b->number is mostly used in linked list*/
printf("%d \n %d \n %d",a.number,b->number,(*b).number);
}
output is 5
5 5
Dot is a dereference operator and used to connect the structure variable for a particular record of structure.
Eg :
struct student
{
int s.no;
Char name [];
int age;
} s1,s2;
main()
{
s1.name;
s2.name;
}
In such way we can use a dot operator to access the structure variable
I'm working my way through the learn c the hard way book and have run into a few issues on Exercise 19. The author said that ex19 was intended for the learners to get to know the macro in c. I have no problem in understanding the concept of that, but I just don't understand everything else. I can't understand how the object prototype is created.
Especilly,what does the following sentense mean?
Since C puts the Room.proto field first, that means the el pointer is
really only pointing at enough of the block of memory to see a full
Object struct. It has no idea that it's even called proto.
the relevant code is this:
// this seems weird, but we can make a struct of one size,
// then point a different pointer at it to "cast" it
Object *el = calloc(1, size);
*el = proto;
can anyone tell me how on earth malloc/calloc exactly works? As far as i know, it just allocate the required number of memory and return the first address. If so, how can the computer know the data struct of the allocated memory? like in the code, after Room *arena = NEW(Room, "The arena, with the minotaur");,you can do this directly arena->bad_guy = NEW(Monster, "The evil minotaur"); how does the computer know there is a bad_guy??
what on earth is the content of *el after the above two statements(Object *el = calloc(1, size); and *el = proto;)?
Any help will be appreciated!!
the link to the exercise: http://c.learncodethehardway.org/book/ex19.html
calloc has the additional feature that it fills the allocated memory with zero bytes, whereas using the equivalent malloc call would require an additional step if all or some of the allocation needs to be zero initially.
In the code
arena->bad_guy = NEW(Monster, "The evil minotaur");
the compiler knows the layout of the struct because the access is through the arena variable, which is declared as a pointer to Room, which is presumably a typedef of a struct.
For the other part, the guarantee of ordering within structs allows a limited form of inheritance in composite structs, or extended structs.
struct A {
int x;
};
struct B {
int foo;
double baloney;
};
struct B (or a pointer to it) can be cast to a (pointer to a) struct A because they both begin with an int. Of course, if you cast the other way, the struct A must have been originally a struct B or access to the baloney field will be undefined. In other words, struct B essentially begins with a struct A.
This may be easier to see if I rewrite my example like this:
struct A {
int x;
};
struct B {
struct A foo;
double baloney;
};
Now you can get a struct A out of struct B in different ways.
struct A a;
struct B b;
a = b.foo; // regular member variable access
struct A *ap = &a;
struct B *bp = &b;
ap = (struct A *)bp; // cast the pointer
ap = & b.foo; // take a pointer from the member variable
ap = & bp->foo; // take a pointer from the member variable via a pointer
All it does is to alloc 1*size bytes. There's nothing magic with malloc/calloc. He is passing the sizeof(T) to the function through that NEW macro and putting it in Object_new's size parameter. So all the function knows is the size in bytes.