Structures Structures allow you to group related information. There are many forms of a struct statement: // form #1 - defines a structType, but not a structure variable // (i.e., it doesn't allocate memory for a variable.) struct structType { attributeDef1; attributeDef2; … }; // form #2 - defines a structure variable, allocating memory struct { attributeDef1; attributeDef2; … } structureVariable; // form 1: defined Employee as a struct type struct Employee { char szSSN[10]; char szFullName[40]; double dHourlyRate; }; // form 2: defined a struct variable, allocating memory struct { char szSSN[10]; char szFullName[40]; double dHourlyRate; } employee; // form 3: define a struct type (Employee) and a // struct variable (employee) struct Employee { char szSSN[10]; char szFullName[40]; double dHourlyRate; // form #3 - defines a strucType and a structure variable, allocating memory struct structType { attributeDef1; attributeDef2; … } structureVariable; } employee; // form #4 - uses a previously defined structType to define a // structure variable, allocating memory struct structType structureVariable; } ; struct Employee employee, employeeMgr; // form 4: define a struct type (Employee) and two // struct variables (employee, employeeMgr) struct Employee { char szSSN[10]; char szFullName[40]; double dHourlyRate; We can also use typedefs to define structures. typedef struct { attributeDef1; attributeDef2; … } typedefStruct; We can then use it in a declaration. typedefStruct structureVariable; Referencing an attribute of a structure variable uses dot notation. structureVariable.attribute Assignments also use the dot notation. typedef struct { char szSSN[10]; char szFullName[40]; double dHourlyRate; } Employee; Employee employee, employeeMgr; printf("SSN=%s, rate=%lf\n" , employee.szSSN, employee.dHourlyRate); printf("Manager is %s\n", employeeMgr.szFullName); employee.dHourlyRate = 12.50; strcpy(employee.szFullName, "Allen Wrench"); We can assign one structure variable into another when they are of the same type. sourceStructureVariable = targetStructureVariable; This copies all of the attributes of the source into the target. employeeMgr = employee; When passing a structure variable to a function, C will make a copy of the value which can be expensive. It is almost always better to pass its address. calculateRaise (&employee); Arrays of Structures To declare an array of structures, specify the array size after the structure variable. struct structType structureVariable[arraySize]; typedefStruct structureVariable[arraySize]; void calculateRaise (Employee *pemployee) { pEmployee->dHourlyRate = pEmployee->dHourlyRate * 1.01; } Employee employeeM[20]; Structures as Attributes In the attribute definition, use either a struct reference or typedef reference // struct reference struct structType { attributeDef1; attributeDef2; struct anotherStructType attributeStructVariable; … } structureVariable; //typedef reference struct structType { attributeDef1; attributeDef2; typedefStruct attributeStructVariable; … } structureVariable; Initialization of Structures When a structure variable is declared, it can be initialized by listing the values in order. If there are few values that need to be initialized, those can be listed using {.variable1=value1, .variable2=value2, …} Arrays of structures can be initialized. The attributes can be initialized in order or you can surround an array item with braces. As stated previously, a structure can be assigned into a structure of the same type. It will copy the entire structure. Slack Bytes (aligning numeric types) What is the size of W2? iExemptionCnt=4, char = 1, dWithholding = 8; sum is 13 Why does sizeof(W2) give 16? typedef struct { int iExemptionCnt; char cFillingStatus; double dWithholdExtra; } W2; // // // // // Number of exemptions M - Married, S - Single X - married but filling as single extra amount to withhold typedef struct { char szSSN[10]; char szFullName[40]; double dHourlyRate; W2 w2; } Employee; Employee employee; To reference dWithholdExtra, reference both structures: dWithholding = dStandardWithholding + employee.w2.dWithholdExtra; Employee employee = { "123456789", "Bill Board" , 12.50, 1, 'M', 100.00 }; Employee employeeMgr = { .szFullName = "I. M. Boss" , .dHourlyRate = 70.00 , .w2.dWithholdExtra = 300.00 }; Employee employeeM[5] = { { "123456789", "Bill Board", 12.50, 1, 'M', 100.00 } , { "222222222", "Peg Board", 15.00, 1, 'M', 150.00 } , { "333333333", "Emory Board", 10.00, 0, 'S', 0.00 } }; employeeMgr = employee; employeeM[3] = employeeMgr; sizeof(W2) gives 16 sizeof(Employee) gives 80 Example for W2: What is the size of Employee?ssn= 10, name=40, dHourlyRate=8; W2 = ? Why does sizeof(Employee) give 80? It is because of slack bytes. It can be easier to read and write 4 byte numeric values if their addresses are a multiple of 4. 8 byte numeric values must be aligned to addresses that are a multiple of 8 for many architectures. Address Variable Size 1000 iExemptionCnt 4 cFillingStatus 1004 1 1008 dWithholding 8 So, there are 3 slack bytes between cFillingStatus and dWithholding. sizeof(W2) = 4+1+3+8 = 16 Example for Employee: Address Variable Size szSSN 2000 10 szFullName 2010 40 2056 8 dHourlyRate 2060 16 W2 There are 6 slack bytes after szFullName. sizeof(Employee) = 10+40+6+8+16 = 80