Download presentation
Presentation is loading. Please wait.
1
C Structures and Memory Allocation
There is no class in C, but we may still want non-homogenous structures So, we use the struct construct (struct for “structure”) A struct is a data structure that comprises multiple types, each known as a member each member has its own unique name and a defined type Example: student struct name (char[ ]), age (int), GPA (float or double), hours (int), sex (char), major (char[ ]), etc If we want to create a structure that can vary in size, we will allocate the struct on demand and attach it to a previous struct through pointers here, we examine structs, allocation techniques, and linked structures
2
The struct Definition struct is a keyword for defining a structured declaration Format: name represents this structure’s tag and is optional we can provide the tag and use it to declare variables or we can declare variables immediately after the } and before the ; at the end of the struct or both We can use typedef to define a shortened name for the type when it comes to variable declarations and parameter passing typedef will be covered later in these notes struct name { type1 name1; type2 name2; … }; name1 and name2 are members of name
3
Examples struct { int x; int y; } p1, p2; p1 and p2 both have the defined structure, containing an x and a y, but do not have a tag struct point { int x; int y; }; struct point p1, p2; p1 and p2 are both points, containing an x and a y value struct point { int x; int y; } p1, p2; same as the other two versions, but united into one set of code, p1 and p2 have the tag point The first approach above is the typical way to use struct, although you can also use the third approach as a shortcut to define the struct and then declare variables. You should never use the middle approach. For the first and last sets of code, point is a defined tag and can be used in later code to declare other variables and to type parameters, but in the middle code, there is no tag, so there is no way to reference more variables of this structure without redefining the structure later in the code
4
Accessing structs A struct is much like an array
The structure stores multiple data so you need to reference a specific member within the struct rather than the entire structure use the . operator as in student.firstName or p1.x and p1.y if the variable (student, p1) is a pointer, we use -> instead as in pointerToStudent->firstName (we cover this shortly) There are four operations you can apply to the entire struct initialization (similar to an array) as in struct point p1 = {5, 10}; assignment of two of the same type of structs as in p1 = p2; passing a struct as a parameter as in foo(p1); obtaining the address of a struct as in &p1 Notice that struct assignment (p1 = p2) requires multiple copying of values. If the struct had 10 members, then p1 = p2 would perform 10 copying actions. This is different than arrays where a = b means “copy the pointer b into the variable a” so that an array of 1000 items only requires 1 copying action. Of course in the case of arrays, you are not creating a new array but instead just having two variables point at the same array.
5
structs as Parameters Structs can be passed as parameters and functions can return structs To receive a struct as a parameter, use struct tag name as in void foo(struct point x, struct point y) {…} for this, the struct must have a tag You can return an entire struct in the return statement of a function for this, again, the struct must have a tag struct point createPoint(int a, int b) { struct point temp; temp.x = a; temp.y = b; return temp; } Although C has no objects and so no constructors, code like that on the left can serve to act like a constructor for a struct
6
Inputting a struct in a Function
#include <stdio.h> struct point { int x; int y; }; void getStruct(struct point); void output(struct point); void main( ) { struct point p1 = {0, 0}; getStruct(p1); output(p1); } void getStruct(struct point p) { scanf("%d", &p.x); scanf("%d", &p.y); printf("%d, %d", p.x, p.y); } void output(struct point p) { To the right is some basic code to input into a struct point and then print out the results Assume the user enters 5 and 10 The output in getStruct is 5, 10 The output in output is 0, 0, why? Remember that parameters are passed by copy Unlike an array, whose variable is actually storing the starting address of the array, a struct is a multi-value variable Passing it by copy means that p1.x and p1.y are passed by copy getStruct inputs the two values properly but into copies of p1, not into p1 Notice that we are initializing y to {0, 0} because y will not get a new value during the getStruct function, and we need y to have values for it to print.
7
One Solution For Input In our previous solution, we passed the struct by copy into the function and manipulated the copy in the function, but nothing was returned We could instead not pass any parameter to getStruct in getStruct, create a temporary struct point and input into it then return the local struct using a return statement we have to modify our function call as now we are receiving a struct struct point getStruct( ) { struct point temp; scanf(“%d”, &temp.x); scanf(“%d”, &temp.y); return temp; } void main( ) { struct point p1 = {0, 0}; p1 = getStruct( ); output(p1); } Here, we no longer need to initialize y, but it is good practice. Another option, covered next, is to pass the address of p1 but this requires understanding how to reference members through a pointer
8
Pointers to Structs The solution on the previous slide two flaws:
It requires twice as much memory we needed 2 struct points, one in main and one in the input function It requires copying each member of temp back into the members of the original struct with our struct point, this is not significant as there are only two members, but for a struct with dozens or hundreds of members, this becomes inefficient Instead, we might pass the address of the struct we receive not the struct but a pointer to the struct we are only passing one item, an address, and need memory space for one item, an address If we have a pointer to a struct, access to the members is through -> instead of . For instance, p1->x, p1->y instead of p1.x, p1.y
9
Pointer-based Example
#include <stdio.h> struct point { // a global definition, the struct point is known in all of int x, y; // these functions }; void getStruct(struct point *); // input into a point void output(struct point); // output a point void main( ) { struct point p1; // declare p1 to be a struct point getStruct(&p1); // input values into p1 output(p1); // send p1 requires 2 copying actions } void getStruct(struct point *p) { // notice the notation here: &ptr->member scanf("%d%d", &p->x, &p->y); void output(struct point p) // same notation, but without the & { printf("%d %d\n", p.x, p.y); Pointer-based Example
10
Nested structs In order to provide modularity, it is common to use already-defined structs as members of additional structs Recall our point struct, now we want to create a rectangle struct the rectangle is defined by its upper left and lower right points struct point { int x; int y; } struct rectangle { struct point pt1; struct point pt2; If we have struct rectangle r; Then we can reference r.pt1.x, r.pt1.y, r.pt2.x and r.pt2.y Now consider the following struct rectangle r, *rp; rp = &r; Then the following are all equivalent r.pt1.x rp->pt1.x (r.pt1).x (rp->pt1).x But not rp->pt1->x (since pt1 is not a pointer to a point)
11
Arrays of structs To declare an array of structs (once you have defined the struct): struct rectangle rects[10]; rects now is a group of 10 structures (that consist each of two points) You can initialize the array as normal where each struct is initialized as a { } list as in {5, 3} for a point or {{5, 3}, {8, 2}} for a rectangle The array of structs will be like the array of classes that we covered in 260/360, we will use this data structure if we want to create a database of some kind and apply such operations as sorting and searching to the structure
12
Example struct point{ int x int y; }; struct rectangle {
struct point p1; struct point p2; void printRect(struct rectangle r) { printf("<%d, %d> to <%d, %d>\n", r.p1.x, r.p1.y, r.p2.x, r.p2.y); } void main( ) int i; struct rectangle rects[ ] = {{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}; // 2 rectangles for(i=0;i<2;i++) printRect(rects[i]); Example
13
typedef typedef is used to define new types
Syntax: typedef description name; Description is an existing type (or a struct definition) and name is the name you want to use in the future typedef, if used right, can promote readability but is otherwise not very useful typedef int Length; // Length is now equivalent to the type int typedef *char[10] Strings; // Strings is the name of a type for an array of 10 strings struct node { // declares a node structure that contains int data; // a data item and a pointer to a struct of type node struct node *next; }; typedef struct node aNode Now we can use aNode instead of struct node to declare nodes or in parameter lists in function headers/prototypes
14
Memory Allocation All of the variables (including structs and array) that we have used to this point of the semester have been allocated statically (at compile time) Dynamic memory allocation allows us to create storage for variables at run-time for instance, once we know the size we need for the structure we might dynamically allocate an array to be of some size as input by the user, or use array doubling if we need more space we might implement a linked structure where we have a structure whose size equals the number of elements stored in it dynamic allocation in Java occurs with the word new in C, we use three functions from stdlib.h malloc – allocate 1 item of the given size calloc – allocate n items of the given size (for dynamic array creation) free – return the given item to the heap
15
Why Dynamic Allocation?
Dynamic allocation has run-time overhead It takes time to allocate a new chunk of memory You are forced to use pointers to point at dynamically allocated memory because heap memory contents are nameless You have to free up any item you are no longer using or that memory is lost known as a memory leak On the other hand, declaring a static sized array (e.g., int a[100]) Restricts your usage – you are limited to that size May be wasteful of memory (you create a large array not knowing what size you need and you only use a small portion of it)
16
malloc and calloc Syntax Both malloc and calloc return void pointers
pointer = (type *)malloc(sizeof(type)); pointer = (type *)calloc(n, sizeof(type)); Both malloc and calloc return void pointers you must properly cast the returned value Use calloc for an array of n elements of type unlike int a[100]; n can be a variable so that the array’s size can vary at run-time input from the user, or altered from an earlier n, for instance when doing array doubling n becomes n*2 use malloc to create nodes in a linked structure little need to dynamically allocate a primitive type like an int for calloc, the type will often be a primitive type, for instance to create a dynamically sized array of ints
17
calloc example Create an array of 10 ints and fill the array
We later discover that we need a larger sized array, use calloc to double the array’s size An example of malloc is given on the web site rather than here as it is too large to fit #include <stdio.h> #include <stdlib.h> // needed for calloc/free void main() { int i; int *x, *y; // x will point to our array, y is a temp pointer x = (int *) calloc(10, sizeof(int)); // x now points to an array of 10 ints for(i=0;i<10;i++) x[i] = i; // fill the array with values … // oops, need more room than 10 y = (int *) calloc(20, sizeof(int)); // create an array of 20, temporarily … // pointed to by y for(i=0;i<10;i++) y[i] = x[i]; // copy old elements of x into y free(x); // release memory of old array x = y; // reset x to point at new, bigger array for(i=10;i<20;i++) x[i] = i; // add the new elements }
18
Linked Structures Although calloc is a convenient way to increase the size of an array, it comes with a cost Array doubling requires n operations (to copy the old array into the new) Having to do array doubling many times as you increase an array’s size eventually becomes inefficient An alternative is to use a linked structure For each item stored in the structure, have a node Add a node by allocating it from the heap and adjusting pointers so that a node in the structure points at the new node and the new node points at the next node in the structure This creates a linked structure, there are usually two forms: lists and arrays (although we can also have linked graphs and others)
19
Declarations for Nodes
struct node { int data; struct node *next; }; struct node *front; front is a pointer to the first node in a linked list. It may initially be NULL. Traversing our linked list might use code like this: struct node *temp = front; while(temp!=NULL) { // process temp temp=temp->next; } struct treeNode { int data; struct treeNode *left; struct treeNode *right; }; Our root node will be declared as struct treeNode *root; It is common in trees to have the root node point to the tree via the right pointer only with the left pointer remaining NULL See the example code on the website for linked lists, we won’t cover trees here
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.