Skip to content
UoL CS Notes

Custom Types, String Functions & Storage Classes

COMP281 Lectures

struct

struct is a user-defined datatype. It is used to construct complex datatypes from existing ones.

struct Syntax

struct [struct_tag] {
	/* member variable 1 */
	/* member variable 2 */
	/* member variable 3 */
}[struct_variables];	// <-- remember the semicolon
  • struct_tag - The name for the structure (optional).

You can then define a struct like so:

struct Employee {
	char name[50];
	int age;
	char gender;
	float salary;
} employee1, employee2;

Accessing struct Members

To assign a value to a struct member, the member name must be liked with the struct variable using a dot . operator:

#include <stdio.h>
#include <string.h>

struct Lecturer {
	char name[50];
	char *room[20];
	int age;
};

int main() {
	struct Lecturer lec;
	strcpy(lec.name, "Phil Jimmieson");
	*lec.room = "Ashton 1.20";
	printf("Name: %s\n", lec.name);
	printf("Room: %s\n", *lec.room);
	return 0;
}

Be aware that you cannot assign structure arrays in the normal way. Either use strcpy or use pointers.

You can also initialise the struct like so:

struct Lecturer lec = {"Phil Jimmieson", "Ashton 1.20", 69};

This way you don’t have to mess with array types.

Array of struct

You can initialise arrays of structs in the normal way:

struct Lecturer lec[4];
lec[0] = {"Phil Jimmieson", "Ashton 1.20", 69};

Nested struct

struct Student {
	char[30] anme;
	int age;
	struct Address {
		char[50] locality;
		char[50] city;
		int pincode;
	} addr;
};

Pointers to struct

#include <stdio.h>

struct point {
	int x;
	int y;
	double dist;
};

void init_point(struct point *p) {
	/* Normal Way */
	(*p).x = (*p).y = 0;
	(*p).dist = 0.0;
	
	/* Syntactic Sugar */
	p->x = p->y = 0;
	p->dist = 0.0;
}

int main() {
	struct point p;	// allocate structure
	struct point *pt = &p;	// allocate pointer to struc
	init_point(pt);
	printf("x=%d\n", pt->x);
	return 0;
}

typedef

typedef allows us to assign alternative names to existing datatypes.

Defining a typedef

The syntax takes the following form:

typedef <existing_name> <alias_name>

For example, we can use this to shorten double-barrelled types:

typedef unsigned long ulong;

We can also use this in conjunction with struct to define new types:

typedef struct { // no name is used
	int x;
	int y;
	double dist;
} Point, *pointPtr;

From this we now have:

  • A new datatype called Point.
  • A new type of pointer to the custom type called pointPtr.

We can also use it to give an alias for pointers to a type:

typedef int* IntPtr;
IntPtr x, y, z;

union

union is a special datatype allowing us to store different datatypes in the same physical memory location. A union can have many members by only one member can contain a value at any given time.

union Syntax

The syntax of union is very similar to struct:

union Example {
	int i;
	float f;
	char str[20];
} e;

The difference is that the memory allocated for union is based on the largest type that it can store, instead of the sum of the type sizes.

Accessing union Members

This is very similar to assessing struct members:

#include <stdio.h>
#include <string.h>

union Data {
	int i;
	float f;
	char str[20];
};

int main() {
	union Data data;
	data.i = 66;
	data.f = 99.9;
	strcpy(data.str, "comp281");
	
	/* only data.str will print correctly */
	printf("data.i:\t%d\n", data.i);
	printf("data.f:\t%d\n", data.f);
	printf("data.str:\t%d\n", data.str);
	return 0;

The difference is that writing to additional members will overwrite previous ones.

Strings

There is no specific datatype for strings, they are just arrays of char terminated by \0 (NUL).

You should be aware of the extra NUL character when calculating the length of strings.

String Functions

strcat()

For concatenating two strings:

char *strcat(char *s1, const char *s2);

Parameters:

  • s1 - A pointer to a string that will be modified.
  • s2 - A pointer to a string that will be appended to the end of s1.

Returns:

  • A pointer to s1 (where the resulting string resides).

strcpy()

For copying one string into another:

char *strcpy(char *dest, const char *src);

Parameters:

  • dest - The pointer to the destination char array where the content is to be copied.
  • src - The string to be copied.

Returns:

  • A pointer to the destination string.

strlen()

Returns the length of a string:

size_t strlen(const char *s);

Parameters:

  • s - The string whose length is to be found.

Returns:

  • The length of the string pointed to by s.

    This does not include the NUL character in the length calculation.

strcmp()

For comparing two strings:

int strcmp(const char *str1, const char *str2);

Parameters:

  • str1 - The first string to be compared.
  • str2 - The second string to be compared.

Returns:

  • $0$ - If s1 and s2 are the same.
  • $<0$ - If s1 < s2.
  • $>0$ - If s1 > s2.

strchr()

For searching for the first occurrence of a character:

char *strchr(const char *str, int c);

Parameters:

  • str - The string to be searched in.
  • c - The character to be searched for.

Returns:

  • A pointer to the first occurrence of the character c in the string str.
  • NULL if the character is not found.

Storage Classes

Each variable has a storage class which decides the scope, default initial value and lifetime. The following storage classes are mostly used:

Automatic Variables

  • Scope - Local to the function block when they are defined.
  • Default Initial Value - Garbage.
  • Lifetime - Till the end of the function where they are defined.

They can be used in the following two ways:

int detail;
auto int details; 

If you have no specific need, use this type of variable.

External (Global) Variables

  • Scope - Not bound by any function; available everywhere.
  • Default Initial Value - 0 (Zero)
  • Lifetime - Until the program finishes executing.

Global values can be changed by any function in the program and are declared outside of the scope of any functions:

#include <stdio.h>

int meaningOfLife = 42;

int main() {
	printf("The meaning of life, the universe and everything is: %d.\n", meaningOfLife);
}

extern

If we want to include global variables from included files then we need to use the extern keyword:

#include <stdio.h>
#include "file.c"

int main() {
	extern int a;
	printf("%d", a);
	return 0;
}

Static Variables

This tells the compiler to persist the variable until the end of the program:

  • Scope - Local to the block in which the variable is defined.
  • Default Initial Value - 0 (Zero)
  • Lifetime - Until the program finished executing.

Instead of creating and destroying a variable every time is goes in and out of scope, a static variable is initialised only once.

This is not the same as a constant.

The following program:

#include <stdio.h>

void test();

int main() {
	test();
	test();
	test();
	return 0;
}

void test() {
	static int a = 0;
	a++;
	printf("%d\t", a);
}

will product the following output:

1	2	3

Register Variables

Tells the compiler to store the variable in a CPU register:

  • Scope - Local to the function in which it is declared.
  • Default Initial Value - Garbage
  • Lifetime - Until the end of the function in which the variable is defined.

We can use them like so:

register int number

We cannot get the address of register variables.