Fundamental C - Basic Structs |
Written by Harry Fairhead | ||||
Monday, 29 April 2019 | ||||
Page 3 of 3
Pointers to StructsUsing value semantics for structs makes reasonable sense if the struct is small and uses only a small amount of memory. The reason arrays use reference semantics and structs use value semantics is that generally arrays are large whereas structs are small. Of course, there are times when structs are not small – mostly when one or more of the fields is an array. Once structs get bigger then you should pass them by reference. How big is it reasonable to pass a struct by value? The answer depends on the machine architecture you are working with but the important point is that the struct’s values are usually passed on the stack so it is the stack size that matters, not the overall amount of memory available. This is particularly relevant if you pass a large struct to a function which then passes it to another function and so on. Each function call allocates the struct on the stack and so uses up increasing amounts of memory – this is particularly important in recursive calls. In practice, things are more complex because the compiler could put the struct into a register and avoid the use of the stack, but this depends on the struct being very small and there being a register available for use. In nearly all cases, it is faster to pass a struct by reference and this is generally considered to be best practice unless there is a really good reason not to. How do you pass or return a struct by reference? Easy, you simply use a pointer to the struct. For example, the previous addToAge function that didn’t work because person was passed by value, can be made to work by passing and using a pointer to the struct: void addToAge(struct myStruct *person) { (*person).age = (*person).age + 1; } Notice that the parentheses are needed because the dereference operator has a lower precedence than the dot operator. Without the parentheses the expression would be equivalent to *(person.age), which wouldn’t evaluate correctly. Now you have to call addToAge using a pointer: addToAge(&me); and in this case the age field of me is changed by the function, which is what you would expect. You can use a pointer to struct to return a struct but as in the case of an array the struct so returned cannot be a local variable. In other words you have to use malloc to allocate the memory on the heap. For example, the makePerson function can be rewritten to create a struct on the heap: struct myStruct* makePerson(char *name,int age){ struct myStruct *person= The cast isn’t actually necessary but it makes clear what you intend. Notice that the function now returns a pointer to the struct and has to be called using: struct myStruct *me = makePerson("harry",19);
The only downside of using a pointer to struct is the slightly cumbersome way you have to dereference the pointer within parentheses. To make this slightly easier, C introduced the -> notation which dereferences the pointer and accesses the field in one go, i.e. it’s the equivalent of * and dot. For example the makePerson function could be written: struct myStruct* makePerson(char *name,int age){ struct myStruct *person= and to print the fields you can use: printf("%d %s\n", me->age, me->name); It is generally considered good practice to use the arrow operator -> when you have a pointer to struct. Notice that you can’t simply use pointer arithmetic to access the fields of a struct. The reason is that adding one to a struct pointer treats it as if it was an array of structs and so it adds sizeof(struct) to the pointer. If you really want to access the fields you have to cast the pointer to the type of the first field and add one, then the next field and add one and so on until you reach the field of your choice. Even this isn’t likely to work because of padding – see later. In short don’t try to access the fields of structs using pointer arithmetic, use the arrow -> notation. Sections in chapter but not in this extract:
Summary
Fundamental C: Getting Closer To The MachineNow available as a paperback and ebook from Amazon.
Also see the companion volume: Applying C <ASIN:1871962609> <ASIN:1871962463> <ASIN:1871962617> <ASIN:1871962455>
Harry Fairhead is the author of Raspberry Pi IoT in C (I/O Press). This extract is from his new book, Fundamental C, where he takes an in-depth look at C for use in any close-to-the-hardware context. Related ArticlesRemote C/C++ Development With NetBeans Getting Started With C/C++ On The Micro:bit To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.
Comments
or email your comment to: comments@i-programmer.info
|
||||
Last Updated ( Monday, 27 May 2019 ) |