0% found this document useful (0 votes)
0 views58 pages

b3b36prg Lec05 Handout

Hand

Uploaded by

griffocrypto68
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
0 views58 pages

b3b36prg Lec05 Handout

Hand

Uploaded by

griffocrypto68
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 58

Data types: Struct, Union, Enum, Bit Fields

Jan Faigl

Department of Computer Science


Faculty of Electrical Engineering
Czech Technical University in Prague

Lecture 05
B3B36PRG – Programming in C

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 1 / 68


Overview of the Lecture
■ Part 1 – Data types
Structures – struct
Unions
Type definition – typedef
Enumerations – enum
K. N. King: chapters 16 and 20
Bit-Fields
■ Part 2 – Assignment HW 05

■ Part 3 – Coding Examples (optional)


Pointer Casting - Print Hex Values
Casting Pointer to Array
String Sorting
Simple Calculator
Casting Pointer to Array
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 2 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Part I
Data types – Struct, Union, Enum and Bit Fields

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 3 / 68


Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Structures, Unions, and Enumerations

■ Structure is a collection of values, possibly of different types.


■ It is defined with the keyword struct.
■ Structures represent records of data fields.
■ Union is also a collection of values, but its members share the same storage.
Union can store one member at a time, but not all simultaneously.
■ Enumeration represents named integer values.

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 4 / 68


Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

struct
■ Structure struct is a finite set of data field members that can be of different type.
■ Structure is defined by the programmer as a new data type.
■ It allows storing a collection of the related data fields.
■ The size of each data field has to be known at the compile time.
■ Each structure has a separate name space for its members.
■ Definition of the compound type (struct) variable user_account.
#define USERNAME_LEN 8 Using anonymous structure type definition.
struct {
int login_count;
char username[USERNAME_LEN + 1]; // compile time array size definition!
int last_login; // date as the number of seconds
// from 1.1.1970 (unix time)
} user_account; // variable of the struct defined type
■ The definition is like other variable definition, where struct {...} specifies the type and
user_account the variable name.
■ We access the struct’s variable members using the . operator, e.g.,
user_account.login_count = 0;
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 6 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Initialization of the Structure Variables and Assignment Operator


■ Structure variables can be initialized in the declaration.
■ In C99, we can also use the designated initializers.
1 struct {
2 int login_count;
3 char name[USENAME_LEN + 1];
4 int last_login;
5 } user1 = { 0, "admin", 1477134134 }, //get unix time ‘date +%s‘
6 // designated initializers in C99
7 user2 = { .name = "root", .login_count = 128 };

9 printf("User1 ’%s’ last login on: %d\n", user1.name, user1.last_login);


10 printf("User2 ’%s’ last login on: %d\n", user2.name, user2.last_login);

12 user2 = user1; // assignment operator structures


13 printf("User2 ’%s’ last login on: %d\n", user2.name, user2.last_login);
lec05/structure_init.c
■ The assignment operator = is defined for the structure variables of the same type.
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 7 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Structure Tag
■ Declaring a structure tag allows to identify a particular structure and avoids repeating
all the data fields in the structure variable.
struct user_account {
int login_count;
char username[USERNAME_LEN + 1];
int last_login;
}; Notice VLA is not allowed in structure type because the size of the structure needs to be known and determined.

■ After creating the user_account tag, variables can be defined as follows.


struct user_account user1, user2;

■ The defined tag is not a type name, therefore it has to be used with the struct keyword.
■ The new type can be defined using the typedef keyword.
typedef struct { ... } new_type_name;

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 8 / 68


Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Example of Defining Structure


■ Without definition of the new type (using typedef) adding the keyword struct
before the structure tag is mandatory.
struct record { typedef struct {
int number; int n;
double value; double v;
}; } item;
record r; /* THIS IS NOT ALLOWED! */
/* Type record is not known */

struct record r; /* Keyword struct is required */


item i; /* type item defined using typedef */
■ The defined struct type (by using typedef) can be used without the struct keyword.
lec05/struct.c
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 9 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Structure Tag and Structure Type


■ We define a new structure tag record using struct record.
struct record {
int number;
double value;
};
■ The tag identifier record is defined in the name space of the structure tags.
It is not mixed with other type names.
■ By Using the typedef, we introduce a new type named record. Or any other name.
typedef struct record record;
■ We define a new identifier record as the type name for the struct record.
■ Structure tag and definition of the type can be combined.
typedef struct record { typedef struct struct_name {
int number; int number;
double value; double value;
} record; } type_name;
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 10 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Example struct – Assignment


■ The assignment operator = can be used for two variables of the same struct type.
Note that, the size of the variable is known.
struct record { typedef struct {
int number; int n;
double value; double v;
}; } item;
struct record rec1 = { 10, 7.12 };
struct record rec2 = { 5, 13.1 };
item i;
print_record(rec1); /* number(10), value(7.120000) */
print_record(rec2); /* number(5), value(13.100000) */
rec1 = rec2;
i = rec1; /* THIS IS NOT ALLOWED! */
// Variables are not of the same type formally.
print_record(rec1); /* number(5), value(13.100000) */
lec05/struct.c
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 11 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Example struct – Direct Copy of the Memory


■ Having two structure variables of the same size, the content can be directly copied
using memory copy. E.g., using memcpy() from <string.h>.
struct record r = { 7, 21.4};
item i = { 1, 2.3 };
print_record(r); /* number(7), value(21.400000) */
print_item(&i); /* n(1), v(2.300000) */
if (sizeof(i) == sizeof(r)) {
printf("i and r are of the same size\n");
memcpy(&i, &r, sizeof(i));
print_item(&i); /* n(7), v(21.400000) */
}
■ Notice, in the example, the interpretation of the stored data in both structures is iden-
tical. In general, it may not be the case.
lec05/struct.c

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 12 / 68


Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Size of Structure Variables


■ Data representation of the structure may be different from the sum of sizes of the
particular data fields (types of the members).
struct record { typedef struct {
int number; int n;
double value; double v;
}; } item;
printf("Size of int: %lu size of double: %lu\n", sizeof(int),
sizeof(double));
printf("Size of record: %lu\n", sizeof(struct record));
printf("Size of item: %lu\n", sizeof(item));

Size of int: 4 size of double: 8


Size of record: 16
Size of item: 16 lec05/struct.c
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 13 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Size of Structure Variables 1/2


■ Compiler might align the data fields to the size of the word (address) of the particularly
used architecture. E.g., 8 bytes for 64-bits CPUs.
■ A compact memory representation can be explicitly prescribed for the clang and gcc
compilers by the __attribute__((packed)).
struct record_packed {
int n;
double v;
} __attribute__((packed));
■ Or typedef struct __attribute__((packed)) {
int n;
double v;
} item_packed;
lec05/struct.c

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 14 / 68


Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Size of Structure Variables 2/2


printf("Size of int: %lu size of double: %lu\n",
sizeof(int), sizeof(double));

printf("record_packed: %lu\n", sizeof(struct record_packed));

printf("item_packed: %lu\n", sizeof(item_packed));

Size of int: 4 size of double: 8


Size of record_packed: 12
Size of item_packed: 12 lec05/struct.c

■ The address alignment provides better performance for addressing the particular mem-
bers at the cost of higher memory requirements.
Eric S. Raymond: The Lost Art of Structure Packing - http://www.catb.org/esr/structure-packing.

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 15 / 68


Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Accessing Members using Pointer to Structure

■ The operator –> can be used to access structure members using a pointer.
typedef struct {
int number;
double value;
} record_s;

record_s a; // variable a of the type record_s


record_s *p = &a; // variable p of the type pointer (to record_s)

printf("Number %d\n", p->number);

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 16 / 68


Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Structure Variables as a Function Parameter


■ Structure variable can be pass to a function and also returned.
■ We can pass/return the struct itself.
struct record print_record(struct record rec) {
printf("record: number(%d), value(%lf)\n",
rec.number, rec.value);
return rec;
}
■ Struct value – a new variable is allocated on the stack and data are copied.
Be aware of shallow copy of pointer data fields.
■ Or, as a pointer to a structure.
item* print_item(item *v) {
printf("item: n(%d), v(%lf)\n", v->n, v->v);
return v;
}
■ Struct pointer – only the address is passed to the function.
By passing a pointer, we can save copy of large structures to stack.
lec05/struct.c
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 17 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Union – variables with Shared Memory


■ Union is a set of members, possibly of different types.
■ All the members share the same memory. Members are overlapping.
■ The size of the union is according to the largest member.
■ Union is similar to the struct and particular members can be accessed using . or ->
for pointers.
■ The declaration, union tag, and type definition is also similar to the struct.
1 union Nums {
2 char c;
3 int i;
4 };
5 Nums nums; /* THIS IS NOT ALLOWED! Type Nums is not known! */
6 union Nums nums;

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 19 / 68


Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Example union 1/2


■ A union composed of variables of the types: char, int, and double.
1 int main(int argc, char *argv[])
2 {
3 union Numbers {
4 char c;
5 int i;
6 double d;
7 };
8 printf("size of char %lu\n", sizeof(char));
9 printf("size of int %lu\n", sizeof(int ));
10 printf("size of double %lu\n", sizeof(double));
11 printf("size of Numbers %lu\n", sizeof(union Numbers));
12 union Numbers numbers;
13 printf("Numbers c: %d i: %d d: %lf\n", numbers.c, numbers.i, numbers.d);
■ Example output:
size of char 1
size of int 4
size of double 8
size of Numbers 8
Numbers c: 48 i: 740313136 d: 0.000000 lec05/union.c
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 20 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Example union 2/2


■ The particular members of the union:
1 numbers.c = ’a’;
2 printf("\nSet the numbers.c to ’a’\n");
3 printf("Numbers c: %d i: %d d: %lf\n", numbers.c, numbers.i, numbers.d);

5 numbers.i = 5;
6 printf("\nSet the numbers.i to 5\n");
7 printf("Numbers c: %d i: %d d: %lf\n", numbers.c, numbers.i, numbers.d);

9 numbers.d = 3.14;
10 printf("\nSet the numbers.d to 3.14\n");
11 printf("Numbers c: %d i: %d d: %lf\n", numbers.c, numbers.i, numbers.d);
■ Example output:
Set the numbers.c to ’a’
Numbers c: 97 i: 1374389601 d: 3.140000

Set the numbers.i to 5


Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 21 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Initialization of Unions
■ The union variable can be initialized in the declaration.
1 union {
2 char c;
3 int i;
4 double d;
5 } numbers = { ’a’ };
Only the first member can be initialized
■ In C99, we can use the designated initializers.
1 union {
2 char c;
3 int i;
4 double d;
5 } numbers = { .d = 10.3 };

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 22 / 68


Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Type Definition – typedef


■ The typedef can also be used to define new data types, not only structures and unions
but also pointers or pointers to functions.
■ Example of the data type for pointers to double or a new type name for int.
1 typedef double* double_p; ■ The usage is identical to the default data types.
2 typedef int integer;
1 double *x, *y;
3 double_p x, y;
2 int i, j;
4 integer i, j;
■ Definition of the new data types (using typedef) in header files allows a systematic use
of new data types in the whole program.
See, e.g., <inttypes.h>
■ The main advantage of defining a new type is for complex data types such as structures
and pointers to functions.

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 24 / 68


Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Enumeration Tags and Type Names


■ Enum allows to define a subset of integer values and named them.
■ We can define enumeration tag similarly to struct and union.
enum suit { SPADES, CLUBS, HEARTS, DIAMONDS };
enum s1, s2;
■ A new enumeration type can be defined using the typedef keyword.
typedef enum { SPADES, CLUBS, HEARTS, DIAMONDS } suit_t;
suit_t s1, s2;
■ The enumeration can be considered as an int value.
However, we should avoid to directly set enum variable as an integer, as, e.g., value 10
does not correspond to any suit.
■ Enumeration can be used in a structure to declare “tag fields”,
typedef struct {
enum { SPADES, CLUBS, HEARTS, DIAMONDS } suit;
enum { RED, BLACK} color;
} card; By using enum we clarify meaning of the suit and color data fields.
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 26 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Example – Enumerated Type as Subscript 1/4


■ Enumeration constants are integers, and they can be used as subscripts.
■ We can also use them to initialize an array of structures.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>

5 enum weekdays { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY };

7 typedef struct {
8 char *name;
9 char *abbr; // abbreviation
10 } week_day_s;

12 const week_day_s days_en[] = {


13 [MONDAY] = { "Monday", "mon" },
14 [TUESDAY] = { "Tuesday", "tue" },
15 [WEDNESDAY] = { "Wednesday", "wed" },
16 [THURSDAY] = { "Thursday", "thr" },
Jan17
Faigl, 2024
[FRIDAY] = { "Friday", "fri" }, B3B36PRG – Lecture 05: Data types 27 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Example – Enumerated Type as Subscript 2/4


■ We can prepare an array of structures for particular language.
■ The program prints the name of the week day and particular abbreviation.
19 const week_day_s days_cs[] = {
20 [MONDAY] = { "Pondělí", "po" },
21 [TUESDAY] = { "Úterý", "út" },
22 [WEDNESDAY] = { "Středa", "st" },
23 [THURSDAY] = { "Čtvrtek", "čt" },
24 [FRIDAY] = { "Pátek", "pá" },
25 };

27 enum { EXIT_OK = 0, ERROR_INPUT = 101 };

29 int main(int argc, char *argv[], char **envp)


30 {
31 int day_of_week = argc > 1 ? atoi(argv[1]) : 1;
32 if (day_of_week < 1 || day_of_week > 5) {
33 fprintf(stderr, "(EE) File: ’%s’ Line: %d -- Given day of week out of range\n",
__FILE__, __LINE__);
34 return ERROR_INPUT;
35 }
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 28 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Example – Enumerated Type as Subscript 3/4


■ Detection of the user “locale” is based on the set environment variables.
For simplicity we just detect Czech based on occurrence of ’cs’ substring in LC_CTYPE
environment variable.
35 _Bool cz = 0;
36 while (*envp != NULL) {
37 if (strstr(*envp, "LC_CTYPE") && strstr(*envp, "cs")) {
38 cz = 1;
39 break;
40 }
41 envp++;
42 }
43 const week_day_s *days = cz ? days_cs : days_en;

45 printf("%d %s %s\n",
46 day_of_week,
47 days[day_of_week].name,
48 days[day_of_week].abbr);
49 return EXIT_OK;
50 } lec05/demo-struct.c
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 29 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Example – Enumerated Type as Subscript 4/4


$ clang demo-struct.c -o demo-struct

$ ./demo-struct
0 Monday mon

$ ./demo-struct 3
2 Wednesday wed

$ LC_CTYPE=cs ./demo-struct 3
2 Středa st

$ lec05 LC_CTYPE=cs_CZ.UTF-8 ./demo-struct 5; echo $?


4 Pátek pá
0

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 30 / 68


Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Bitwise Operators
■ In low-level programming, such as programs for MCU (micro controller units), we may
need to store information as single bits or collection of bits.
■ We can use bitwise operators to set or extract particular bit, e.g., a 16-bit unsigned
integer variable uint16_t i.
■ Set the 4 bit of i.
if ( i & 0x0010) ...
■ Clear the 4 bit of i.
i &= ∼0x0010;
■ We can give names to particular bits.
35 #define RED 1
36 #define GREEN 2
37 #define BLUE 3

39 i |= RED; // sets the RED bit


40 i &= ~GREEN; // clears the GREEN bit
41 if (i & BLUE) ... // test BLUE bit
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 32 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Bit-Fields in Structures
■ In addition to bitwise operators, we can declare structures whose members represent
bit-fields, e.g., time stored in 16 bits.
typedef struct {
uint16_t seconds: 5; // use 5 bits to store seconds
uint16_t minutes: 6; // use 6 bits to store minutes
uint16_t hours: 5; //use 5 bits to store hours
} file_time_t;

file_time_t time;
■ We can access the members as a regular structure variable.
time.seconds = 10;
■ The only restriction is that the bit-fields do not have address in the usual sense, and
therefore, using address operator & is not allowed.
scanf("%d", &time.hours); // NOT ALLOWED!
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 33 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Bit-Fields Memory Representation


■ The way how a compiler handle bit-fields depends on the notion of the storage units.
■ Storage units are implementation defined (e.g., 8 bits, 16 bits, etc.).
■ We can omit the name of the bit-field for padding, i.e., to ensure other bit fields are
properly positioned.

typedef struct { typedef struct {


unsigned int seconds: 5; unsigned int seconds: 5;
unsigned int minutes: 6; unsigned int : 0;
unsigned int hours: 5; unsigned int minutes: 6;
} file_time_int_s; unsigned int hours: 5;
} file_time_int_skip_s;
// size 4 bytes
printf("Size %lu\n", sizeof( // size 8 bytes because of padding
file_time_int_s)); printf("Size %lu\n", sizeof(
file_time_int_skip_s));
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 34 / 68
Structures – struct Unions Type definition – typedef Enumerations – enum Bit-Fields

Bit-Fields Example
typedef struct {
unsigned int seconds: 5;
unsigned int minutes: 6;
unsigned int hours: 5;
} file_time_int_s;

void print_time(const file_time_s *t)


{
printf("%02u:%02u:%02u\n", t->hours, t->minutes, t->seconds);
}

int main(void)
{
file_time_s time = { // designated initializers
.hours = 23, .minutes = 7, .seconds = 10 };
print_time(&time);
time.minutes += 30;
print_time(&time);

// size 2 bytes (for 16 bit short


printf("Size of file_time_s %lu\n", sizeof(time));
Jan Faigl, 2024
return 0; B3B36PRG – Lecture 05: Data types 35 / 68
Part II
Part 2 – Assignment HW 05

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 36 / 68


HW 05 – Assignment
Topic: Matrix Operations Mandatory: 2 points; Optional: 2 points; Bonus : 5
■ Motivation: Variable Length Array (VLA) and 2D arrays.
■ Goal: Familiar yourself with VLA and pointers. (optional and bonus) Dynamic allocation and structures.

■ Assignment: https://cw.fel.cvut.cz/wiki/courses/b3b36prg/hw/hw05
■ Read matrix expression – matrices and operators (+, -, and *) from standard input (di-
mensions of the matrices are provided).
■ Compute the result of the matrix expression or report an error . Dynamic allocation is not needed!
Functions for implementing +, *, and - operators are highly recommended!
■ Optional assignment – compute the matrix expression with respect to the priority of *
operator over + and - operators. Dynamic allocation is not need, but it can be helpful.
■ Bonus assignment – Read declaration of matrices prior the matrix expression.
Dynamic allocation can be helpful, structures are not needed but can be helpful.

■ Deadline: 20.04.2024, 23:59 AoE (bonus 24.5.2024, 23:59 CEST).

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 37 / 68


Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Part III
Part 3 – Coding Examples
(optional)

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 38 / 68


Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Print Hex Values


■ Representation of the float values. #include <stdio.h>
■ Value 85.125 is 0x42aa4000.
■ Value 0.1 is 0x3dcccccc but encoded 0x3dcccccd. void print_float_hex(float v);
■ Implement a function to print a hex represen-
tation of a float value. int main(void)
{
■ Access to a float value as a sequence of bytes print_float_hex(85.125);
and print individual bytes as hex values using print_float_hex(0.1);
"%02x" in printf(). return 0;
■ Use addressing operator & to get variable address. }
■ Type case to get a pointer to char (a single byte).
■ Use indirect addressing operator * to access to the
variable at the address stored in the pointer vari- void print_float_hex(float v)
able. {
■ Access to a float value as a sequence of bytes ...
and print individual bytes as hex values using }
"%02x" in printf().
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 40 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Print Hex Values – Implementation 1/3


■ Retrive address of variable float v by &v. int main(void)
■ We need access values at the address &v as {
bytes; therefore, we type cast it to a pointer to print_float_hex(85.125);
print_float_hex(0.1);
char value(s).
...
unsigned char *p = (unsigned char*)&v; void print_float_hex(float v)
■ The value at the address stored in p can be {
accessed by the indirect addressing operator *p. unsigned char *p = (unsigned char*)&v;
printf("Value %13.10f is 0x", v);
■ We can advance the next address by increment- for (int i = 0; i < 4; ++i, p = p + 1) {
ing the value stored in p, e.g., p = p + 1;. printf("%02x", *p); // or use p[i]
Because it is a pointer to char, the increment is about }
sizeof(char), i.e., by 1. It is the pointer arithmetic. putchar(’\n’);
}
■ However, the printed values are in the reversed
order than the expected order 0x42aa4000 and $ clang floats.c -o floats && ./floats
0x3dcccccd. Value 85.1250000000 is 0x0040aa42
Value 0.1000000015 is 0xcdcccc3d
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 41 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Print Hex Values – Implementation 2/3


■ Expected hexadecimal representation of the void print_float_hex(float v)
values 85.125 and 0.1 is 0x42aa4000 {
and 0x3dcccccd but the printed values are const _Bool big_endian = is_big_endian();
0x0040aa42 and 0xcdcccc3d, respectively. // cast pointer to float to pointer to char
unsigned char *p = (unsigned char*)&v
■ It is because of the way how multi-byte values + (big_endian ? 0 : 3);
are stored in the memory. For the used archi- printf("Value %13.10f is 0x", v);
tecture (amd64), it is little endian. for (int i = 0; i < 4; ++i) {
printf("%02x",
■ Thus, we need to detect the endianness.
*(big_endian ? p++ : p--)
https://en.wikipedia.org/wiki/Endianness );
}
■ E.g., using a function
printf("\n");
_Bool is_big_endian(void); }
■ and print values in the reversed order.
$ clang floats.c -o floats && ./floats
Value 85.1250000000 is 0x42aa4000
Value 0.1000000015 is 0x3dcccccd
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 42 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Print Hex Values – Implementation 3/3


■ The detection of the endianness can be based #include <stdint.h>
on various techniques.
_Bool is_big_endian(void)
■ Intuitively, we need to store a defined value with {
all zeros but one byte non-zero. union {
uint32_t i;
■ We can take advantage of the union type that char c[4];
allows different views on the identical memory } e = { 0x01000000 };
block. return e.c[0];
1. Define an integer variable with the spec- }
ified size of four bytes, e.g., unit32_t
from stdint.h library.
2. Set the value of 0x01 00 00 00 to the
variable.
3. Check the first byte of the memory repre-
sentation, if it is zero or one.
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 43 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Array and Pointer to Function 1/4


■ Implement a program that creates an array of #ifndef LEN
random integer values using rand() function #define LEN 5
from stdlib.h. Fill random function. #endif
■ The integer values are limited to MAX_NUM set #define MAX_NUM 20
to, e.g., 20, by #define MAX_NUM 20.
■ The default number can be adjusted at the void fill_random(size_t l, int a[l]);
compile time – clang -DLEN=10 program.c. void print(const char *s, size_t l, int a[l]);
■ The array is printed to stdout. Print function. int main(void)
■ The array is sorted using qsort() from {
stdlib.h. Become familiar with man qsort. int a[LEN]; // allocate the array
fill_random(LEN, a); // fill the array
■ The sorted array is printed to stdout.
print("Array random: ", LEN, a);
■ The program is then enhanced by processing // TODO call qsort
program arguments to define the no. of values print("Array sorted: ", LEN, a);
as the first program argument using atoi(). return 0;
}
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 45 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Array and Pointer to Function 2/4


void fill_random(size_t l, int a[l]) ■ See man qsort for qsort synopsis.
{
void qsort(
for (size_t i = 0; i < l; ++i) {
void *base, size_t nmemb, size_t size,
a[i] = rand() % MAX_NUM;
int (*compar)(const void *, const void *)
}
);
}
■ base is the pointer to the initial member.
■ nmemb is the no. of members.
void print(const char *s, size_t l, int a[l]) ■ size is the size of each member.
{ ■ compar is a pointer to the comparision function.
if (s) {
printf("%s", s); int compare(const void *ai, const void *bi)
} {
for (size_t i = 0; i < l; ++i) { const int *a = (const int*)ai;
printf("%s%d", i > 0 ? " " : "", a[i]); const int *b = (const int*)bi;
} //ascending
putchar(’\n’); return *a == *b ? 0 : (*a < *b ? -1 : 1);
} }
Change the order to descending.

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 46 / 68


Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Array and Pointer to Function 3/4

■ Use the function name as the pointer to the ■ Compile and run if the compilation is suc-
function. cessfull using shell logical and operator &&.
int compare(const void *, const void *); $ clang sort.c -o sort && ./sort
Array random: 13 17 18 15 12
int main(void) Array sorted: 12 13 15 17 18
{
int a[LEN]; // do not initialize ■ Use compiler flag -DLEN=10 to define the array
fill_random(LEN, a); length 10.
print("Array random: ", LEN, a);
qsort(a, LEN, sizeof(int), compare); $ clang -DLEN=10 sort.c -o sort && ./sort
print("Array sorted: ", LEN, a); Array random: 13 17 18 15 12 3 7 8 18 10
return 0; Array sorted: 3 7 8 10 12 13 15 17 18 18
}

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 47 / 68


Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Array and Pointer to Function 4/4


■ Extend main() to pass program arguments. ■ We use the Variable Length Array (VLA),
■ Define an error value. which length is determined during the runtime.
enum { ERROR = 100 }; $ clang sort-vla.c -o sort && ./sort
Array random: 13 17 18 15 12 3
int main(int argc, char *argv[]) Array sorted: 3 12 13 15 17 18
{
const size_t len = argc > 1 ? $ clang sort-vla.c -DLEN=7 -o sort && ./sort
atoi(argv[1]) : LEN; Array random: 13 17 18 15 12 3 7
if (len > 0) { Array sorted: 3 7 12 13 15 17 18
int a[len];
fill_random(len, a); $ clang sort-vla.c -o sort && ./sort 11
print("Array random: ", len, a); Array random: 13 17 18 15 12 3 7 8 18 10 19
qsort(a, len, sizeof(int), compare); Array sorted: 3 7 8 10 12 13 15 17 18 18 19
print("Array sorted: ", len, a);
} ■ Be aware the size of the array a is limited by
return len > 0 ? EXIT_SUCCESS : ERROR; the size of the stack, see ulimit -s.
}
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 48 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – String Sorting 1/5


■ Implement a program that sorts program ar- #include <stdio.h>
guments lexicographically using strcmp (from #include <string.h>
string.h) and qsort (from stdlib.h). #include <stdlib.h>
■ Print the arguments. Print function. void print(int n, char *strings[n]);
■ Copy the passed argv to newly allocated mem-
ory on the heap to avoid changes in argv. char* copy(const char *str);
char** copy_strings(int n, char *strings[n]);
■ Exit with -1 if allocation fails.
My malloc function. void* my_malloc(size_t size);
■ Copy strings using strncpy. void release(int n, char **strings);
Copy and copy strings functions.
int string_compare(
■ Sort the copied array of strings with the help const void *p1, const void *p2);
of strcmp. String compare function.
■ Release the allocated memory. Release function. enum { EXIT_OK = 0, EXIT_MEM = -1 };

int main(int argc, char *argv[]);


Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 50 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – String Sorting 2/5


■ Print function directly iterates over strings. ■ Copy call my_malloc and use strncpy.
void print(int n, char *strings[n]) char* copy(const char *str)
{ {
for (int i = 0; i < n; ++i) { char *ret = NULL;
printf("%3d. \"%s\"\n", i, strings[i]); if (str) {
} size_t len = strlen(str);
} ret = my_malloc(len + 1);// +1 for ’\0’
strncpy(ret, str, len + 1);//+1 for ’\0’
■ Allocate array of pointers to char. }
char** copy_strings(int n, char *strings[n]) return ret;
{ }
char** ret = my_malloc(n * sizeof(char*)); ■ The length of the string (by strlen) is without
for (int i = 0; i < n; ++i) { the null terminating ’\0’.
ret[i] = copy(strings[i]); ■ The copy of the string content needs to include
} the null terminating character as well.
return ret;
}
We take advantage that the allocation succeeds,
or the program terminates with an error.
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 51 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – String Sorting 3/5


■ Dynamic allocation calls malloc and termi- ■ The dynamically allocated array of pointers to
nates the program on error. (dynamically allocated) strings needs releasing
the strings and then the array itself.
void* my_malloc(size_t size)
{ void release(int n, char **strings)
void *ret = malloc(size); {
if (!ret) { if (strings && *strings)
fprintf(stderr, return;
"ERROR: Mem allocation error!\n");
exit(EXIT_MEM); for (int i = 0; i < n; ++i) {
} if (strings[i]) {
return ret; free(strings[i]); //free string
} }
}
free(strings); // free array of pointers
}

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 52 / 68


Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – String Sorting 4/5


■ Synopsis of the qsort function, see man qsort.
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *)
); It passes pointers to the array elements as pointers to constant values.
■ We call qsort on an array of pointers to strings, which are pointers to char.
char **strings = copy_strings(n, argv);
qsort(strings, n, sizeof(char*), string_compare);
■ We cast the pointer to void as a pointer to pointer to char for accessing the string.
int string_compare(const void *p1, const void *p2)
{
char * const *s1 = p1; // qsort passes a pointer to the array item (string)
char * const *s2 = p2;
return strcmp(*s1, *s2);
}
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 53 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – String Sorting 5/5


■ Call qsort on array of pointers. ■ clang str_sort.c && ./a.out 4 2 a z c
int main(int argc, char *argv[])
Arguments: Sorted arguments:
{
0. "./a.out" 0. "./a.out"
int ret = EXIT_OK;
1. "4" 1. "2"
const int n = argc;
2. "2" 2. "4"
printf("Arguments:\n");
3. "a" 3. "a"
print(argc, argv);
4. "z" 4. "c"
5. "c" 5. "z"
char **strings = copy_strings(n, argv);
qsort(
strings, n,
sizeof(char*), string_compare
■ Further tasks.
); ■ Implement strings as an array of pointers with-
out explicit number of items, but with terminating
NULL pointer.
printf("\n Sorted arguments:\n"); ■ Implement allocation for strings as a single contin-
print(n, strings); uous block of memory storing all the strings sepa-
release(n, strings); rated by ’\0’.
return ret;
}
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 54 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Simple Calculator 1/6


■ Implement a calculator that processess an in- enum status { EXIT_OK = 0, ERROR_INPUT = 100,
put string containing expression with interger ERROR_OPERATOR = 101 };
values and operators ’+’, ’-’, ’*’.
enum status printe(enum status error);
Sum, sub, and mult functions.
■ It reports error and return error values 100 if int main(int argc, char *argv[])
value is not an interger and 101 in the case of {
unsupported operator. enum status ret = EXIT_OK;
...
■ Use pointer to operation functions. return printe(ret);
■ Process the input step-by-step, avoid reading }
the whole input, print partial results.
enum status printe(enum status error)
■ Handle all possible errors.
{
■ There must by at least single interger value. if (error == ERROR_INPUT) {
■ If an operator is given, it must be valid and fprintf(stderr, "ERROR: Input value\n");
there must be the second operand.
} else if (error == ERROR_OPERATOR) {
■ If end-of-file (input), and the operator is not
given, print the result.
fprintf(stderr, "ERROR: Operator\n");
}
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 56 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Simple Calculator 2/6


■ Implement a calculator that processess an in- int sum(int a, int b); // return a + b
put string containing expression with interger int sub(int a, int b); // return a - b
values and operators ’+’, ’-’, ’*’. int mult(int a, int b);// return a * b
Sum, sub, and mult functions. //define a pointer to a function
■ It reports error and return error values 100 if typedef int (*ptr)(int, int);
value is not an interger and 101 in the case of
unsupported operator. //typedef ptr is needed for the return value
ptr getop(const char *op)
■ Use pointer to operation functions. {
■ Process the input step-by-step, avoid reading int (*operation)(int, int) = NULL;
the whole input, print partial results. if (op[0] == ’+’) {
operation = sum;
■ Handle all possible errors.
} else if (op[0] == ’-’) {
■ There must by at least single interger value. operation = sub;
■ If an operator is given, it must be valid and } else if (op[0] == ’*’) {
there must be the second operand.
operation = mult;
■ If end-of-file (input), and the operator is not
given, print the result.
}
return operation;
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 57 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Simple Calculator 3/6


■ Implement a calculator that processess an in- int r = 1; //the first v1
put string containing expression with interger char opstr[2] = {}; //store the operator
values and operators ’+’, ’-’, ’*’. ptr op = NULL; // function pointer
Sum, sub, and mult functions. int v2; //store the second operand
while (r == 1 && ret == EXIT_OK) {
■ It reports error and return error values 100 if r = (op = readop(opstr, &ret)) ? 1 : 0;
value is not an interger and 101 in the case of // operator is valid and second operand read
unsupported operator. int v3 = op(v1, v2);
■ Use pointer to operation functions. printf("%3d %s %3d = %3d\n",
v1, opstr, v2, v3);
■ Process the input step-by-step, avoid reading v1 = v3; //shift the results
the whole input, print partial results. } else if (!op) { // no operator
■ Handle all possible errors. printf("Result: %3d\n", v1);
r = 0;
■ There must by at least single interger value.
} else if (r != 1) { //no operand
■ If an operator is given, it must be valid and
there must be the second operand. ret = ERROR_INPUT;
■ If end-of-file (input), and the operator is not }
given, print the result. } //end of while
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 58 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Simple Calculator 4/6


■ Implement a calculator that processess an in- enum status ret = EXIT_OK;
put string containing expression with interger int v1;
values and operators ’+’, ’-’, ’*’.
Sum, sub, and mult functions. int r = scanf("%d", &v1) == 1;
ret = r == 0 ? ERROR_INPUT : ret;
■ It reports error and return error values 100 if if (ret == EXIT_OK) {
value is not an interger and 101 in the case of ret = process(ret, v1);
unsupported operator. }
■ Use pointer to operation functions. ...
■ Process the input step-by-step, avoid reading ptr readop(char *opstr, enum status *error)
the whole input, print partial results. {
■ Handle all possible errors. ptr op = NULL; // pointer to a function
int r = scanf("%1s", opstr);
■ There must by at least single interger value.
if (r == 1) {
■ If an operator is given, it must be valid and
there must be the second operand. *error = (op = getop(opstr)) ? *error :
ERROR_OPERATOR;
} // else end-of-file
Jan Faigl, 2024
return op;
B3B36PRG – Lecture 05: Data types 59 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Simple Calculator 5/6


enum status process(enum status ret, int v1)
{
int r = 1; //the first operand is given in v1
char opstr[2] = {}; //store the operator
ptr op = NULL; // function pointer to operator
int v2; //store the second operand
while (r == 1 && ret == EXIT_OK) {
r = (op = readop(opstr, &ret)) ? 1 : 0; // operand read succesfully
if (r == 1 && (r = scanf("%d", &v2)) == 1) { // while ends for r == 0 or r == -1
int v3 = op(v1, v2);
printf("%3d %s %3d = %3d\n", v1, opstr, v2, v3);
v1 = v3; //shift the results
} else if (!op) { // no operator in the input
printf("Result: %3d\n", v1); //print the final results
r = 0;
} else if (r != 1) { //no operand on the input
ret = ERROR_INPUT;
}
} //end of while
return ret;
}
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 60 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Simple Calculator 6/6


1 enum status { EXIT_OK = 0, ERROR_INPUT = 100, ■ Example of program execution.
ERROR_OPERATOR = 101 };
$ clang calc.c -o calc
2 ...
$ echo "1 + 2 * 6 - 2 * 3 + 19" | ./calc
3 typedef int (*ptr)(int, int);
1 + 2 = 3
4 ptr getop(const char *op);
3 * 6 = 18
5 enum status printe(enum status error);
18 - 2 = 16
6 enum status process(enum status ret, int v1);
16 * 3 = 48
48 + 19 = 67
Result: 67
9 int main(int argc, char *argv[])
10 {
$ echo "1 + 2 *" | ./calc; echo $?
11 enum status ret = EXIT_OK;
1 + 2 = 3
12 int v1;
ERROR: Input value
100
14 int r = scanf("%d", &v1) == 1;
15 ret = r == 1 ? ret : ERROR_INPUT;
$echo "1 + 2 a" | ./calc; echo $?
16 if (ret == EXIT_OK) {
1 + 2 = 3
17 ret = process(ret, v1);
Result: 3
18 }
Jan Faigl, 2024 ERROR:
B3B36PRG Operator
– Lecture 05: Data types 61 / 68
Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Casting Pointer to Array 1/4


■ Allocate array of the size ROWS × COLS and fill #define MAX_VALUE 100
it with random integer values with up to two #define ROWS 3
digits, and print the values are an array. #define COLS 4

■ Implement fill and print functions. void fill(int n, int *v);


void print_values(int n, int *a);
■ Implement print function to print matrix of the
size rows × cols. int main(int argc, char *argv[])
■ Cast the array of int values into m - a pointer {
const int n = ROWS * COLS;
of arrays of the size cols.
int array[n];
■ Pass m to the function that prints the 2D array int *p = array;
(matrix) with cols columns.
fill(n, p);
print_values(n, p);
return 0;
}

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 63 / 68


Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Casting Pointer to Array 2/4


■ Allocate array of the size ROWS × COLS and fill void fill(int n, int *v)
it with random integer values with up to two {
digits, and print the values are an array. for (int i = 0; i < n; ++i) {
v[i] = rand() % MAX_VALUE;
■ Implement fill and print functions. }
}
■ Implement print function to print matrix of the
size rows × cols. void print_values(int n, int *a)
■ Cast the array of int values into m - a pointer {
for (int i = 0; i < n; ++i) {
of arrays of the size cols.
printf("%s%i",
■ Pass m to the function that prints the 2D array (i > 0 ? " " : ""),
(matrix) with cols columns. a[i]
);
}
putchar(’\n’);
}

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 64 / 68


Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Casting Pointer to Array 3/4

■ Allocate array of the size ROWS × COLS and fill void print(int rows, int cols, int m[][cols])
it with random integer values with up to two {
digits, and print the values are an array. for (int r = 0; r < rows; ++r) {
for (int c = 0; c < cols; ++c) {
■ Implement fill and print functions. printf("%3i", m[r][c]);
}
■ Implement print function to print matrix of the putchar(’\n’);
size rows × cols. }
■ Cast the array of int values into m - a pointer }
of arrays of the size cols. ■ The number of columns is mandatory to deter-
■ Pass m to the function that prints the 2D array mine the address of the cell m[r][c] in the 2D
(matrix) with cols columns. array (matrix) m.
■ The pointer m can refer to arbitrary number of
rows.

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 65 / 68


Pointer Casting - Print Hex Values Casting Pointer to Array String Sorting Simple Calculator Casting Pointer to Array

Coding Example – Casting Pointer to Array 4/4


■ Allocate array of the size ROWS × COLS and fill #define MAX_VALUE 100
it with random integer values with up to two #define ROWS 3
digits, and print the values are an array. #define COLS 4
...
■ Implement fill and print functions. void print(int rows, int cols, int m[][cols]);
■ Implement print function to print matrix of the int main(int argc, char *argv[])
size rows × cols. {
■ Cast the array of int values into m - a pointer const int n = ROWS * COLS;
int array[n];
of arrays of the size cols.
int *p = array;
■ Pass m to the function that prints the 2D array
(matrix) with cols columns. int (*m)[COLS] = (int(*)[COLS])p;
Try to print the array as matrix with cols
printf("\nPrint as matrix %d x %d\n",
columns and rows columns that is as matrix with ROWS, COLS);
rows×cols and cols×rows, respectively. print(ROWS, COLS, m);
return 0;
}
Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 66 / 68
Topics Discussed

Summary of the Lecture

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 67 / 68


Topics Discussed

Topics Discussed

■ Data types
■ Structure variables
■ Unions
■ Enumeration
■ Type definition
■ Bit-Fields

■ Next: Input/output operations and standard library

Jan Faigl, 2024 B3B36PRG – Lecture 05: Data types 68 / 68

You might also like