FOC UNIT 5

UNIT 5

Arrays –Initialization, Characteristics, one, two and multi dimensional arrays, operations with arrays, Handling of Character Strings-Declaration & Initialization of Strings

Display of Strings with Different Formats, String standard functions

User defined functions–Defining and declaring function prototypes, the return statement

Types of functions, Call by Value, Call by reference, Function returning more values, Function as an argument, Function with operators, Function & decision statements, Function and loop statements, Function with arrays & pointers, Recursion, Pointer to functions, Structures–Features, initialization, structure within structure, array of structures, pointer to structure, Structures and functions, Union, Union of structures,

Pointers– Declaration, Arithmetic operations with pointers, pointers and arrays, pointers and two-dimensional arrays, Array of pointers, pointer to pointer, pointers and strings, void pointers ,Sample Programs,

Preprocessor Directives-#define, #include, #ifndef, #error, #line directives, Developing a C program-Guidelines

COMPILER, which translates the source code into machine code

COMPILER, which translates the source code into machine code. This produces output in a format that the computer can understand.

LINKER

Sometimes the source code is still lacking some parts, so after going through the compiler, the code is passed through a LINKER. This basically “links” the source code to other library or object files so that the final program is produced. Imagine the program being a jigsaw puzzle – the linker simply puts together missing pieces to complete the program.

Declaring Arrays

You need to make a declaration before using an array. To declare an array, you need to specify its data type, its name and, in most cases, its size. Make sure the array has a valid name. Here’s an example:

int arrayOfInts[5];

This reserves memory for an array that to hold five integer values. The number of elements should be enclosed in the square brackets. If you don’t specify the number of elements during the declaration, you have declared an UNSIZED array – the size will be calculated when you insert values into it.

Initializing Arrays

You can assign values to the array in several ways. For example, if I wanted an array to hold the numbers 1 through to 10, I could do this in several ways, as this example demonstrates:

int main() {

int arrayOfInts1[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int arrayOfInts2[10];

int arrayOfInts3[] = {1,2,3,4,5,

6,7,8,9,10}; /* an unsized array */

int arrayOfInts4[10];

int i;

arrayOfInts2[0] = 1;

arrayOfInts2[1] = 2;

arrayOfInts2[2] = 3;

arrayOfInts2[3] = 4;

arrayOfInts2[4] = 5;

arrayOfInts2[5] = 6;

arrayOfInts2[6] = 7;

arrayOfInts2[7] = 8;

arrayOfInts2[8] = 9;

arrayOfInts2[9] = 10;

for(i=0 ; i<10 ; i++) {

arrayOfInts4[i] = i + 1;

}

return 0;

}

Printing Out Arrays

One of the commonest ways to print out the contents of the array is to use a loop. I personally prefer using a for loop, like this:

#include <stdio.h>

int main() {

int anotherIntArray[5] = {1,2,3,4,5};

int i;

for(i=0 ; i<6 ; i++) {

printf(“anotherIntArray[%d] has a value of %d\n”,

i, anotherIntArray[i]);

}

return 0;

}

Output:

I iterated one element too far to demonstrate what happens if you did. As you can see, MSVC++ seemed to print out a random number.

You can also use a loop with scanf to insert elements:

#include <stdio.h>

int main() {

int anotherIntArray[5];

int i;

printf(“Enter 5 integers one by one “);

printf(“pressing return after each one:\n”);

for(i=0 ; i<5 ; i++) {

scanf(“%d”, &anotherIntArray[i]);

}

for(i=0 ; i<5 ; i++) {

printf(“anotherIntArray[%d] has a value of %d\n”,

i, anotherIntArray[i]);

}

return 0;

}

Character Arrays

So far I’ve used arrays of integers in my examples – probably the type I’ve been using the most. You can use arrays for floats and doubles as well as chars.

Character arrays have a special property…

Each element of the array can hold one character. But if you end the array with the NULL CHARACTER, denoted by (that is, backslash and zero), you’ll have what is known as a STRING CONSTANT. The null character marks the end of a string – useful for functions like printf. Time for an example…..

#include <stdio.h>

int main() {

char charArray[8] = {‘F’,’r’,’i’,’e’,’n’,’d’,’s’,”};

int i;

for(i=0 ; i<8 ; i++) {

printf(“charArray[%d] has a value of %c\n”,

i, charArray[i]);

}

printf(“My favourite comedy is %s\n”, charArray);

/* Alternative way */

return 0;

}

Output:

Single Dimensional Arrays

Sometimes it’s inconvenient to call a function that requires a long list of arguments.

One way around this, is to store your variables into an array, then pass a POINTER to the array to the function. This method will be discussed in greater detail in the pointers section, but for now you need to know that the array isn’t actually passed to the function – just the array’s location in the memory. This is known as PASS BY REFERENCE. The name of an array references the array’s location in the memory, its ADDRESS.

#include <stdio.h>

int addNumbers(int fiveNumbers[]); /* declare function */

int main() {

int array[5];

int i;

printf(“Enter 5 integers separated by spaces: “);

for(i=0 ; i<5 ; i++) {

scanf(“%d”, &array[i]);

}

printf(“\nTheir sum is: %d\n”, addNumbers(array));

return 0;

}

int addNumbers(int fiveNumbers[]) { /* define function */

int sum = 0;

int i;

for(i=0 ; i<5 ; i++) {

sum+=fiveNumbers[i]; /* work out the total */

}

return sum; /* return the total */

}

Notice that I’ve left the size of the array blank in both the function declaration and definition – the compiler works it out for you. Also, when I called the function, I passed on the name of the array. This is the equivalent to passing &array[0] – the address of the first element. You’ll learn about the address-of operator later.

Multidimensional Arrays

This is similar to passing 1D arrays but, in the function declarations you must specify all the dimension sizes (but the leftmost one is optional).

#include <stdio.h>

void printArray(int array[][4]); /* declare function */

int main() {

int array[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};

printArray(array);

return 0;

}

void printArray(int array[][4]) { /* define function */

int i, j;

for(i=0 ; i<3 ; i++) {

for(j=0 ; j<4 ; j++) {

printf(“%2d “, array[i][j]);

}

printf(“\n”);

}

}

& – The “Address of” Operator

Before I tell you what a pointer is, I’d have to introduce you to this operator.

It looks familiar – we saw it in the bitwise operators section. However, bitwise AND takes two operands like this: a & b, but the ADDRESS OF operator only takes one on the right: &x.

Recall that when you declare a variable, you reserve bytes in the computer’s memory for that variable. The allocated memory is referenced by the variable name and must be unique.

You can picture the computer’s memory as a very long row of slots. Now, each slot has a unique ADDRESS, which is expressed in hexadecimal format. It’s like a long road of houses – each house has a unique number in decimal format. In each occupied house, there are people.

In our case, the houses are memory slots, and the people are the variables.

Now suppose we wanted to find out where in the memory a variable lives. We can use the address-of operator. &x returns the “address of x” in hex format.

#include <stdio.h>

int main() {

int x = 0;

printf(“Address of x “);

printf(“= 0x%p \n”, &x);

return 0;

}

Output: Address of x = 0x0065FDF4

%p is the format specifier for addresses (%x would still compile OK). 0x in the printf function is there to signify that a hex number follows.

Recall: scanf(“%d”, &x);

– You can translate this as: “take the inputted integer and put it in the address of x“.

Left and Right Values

Now let’s look at the assignment operator:
x = 1; takes the value on the right (e.g. 1) and puts it in the memory referenced by x, say.

Also known as L-VALUES and R-VALUES respectively L-values can be on either side of the assignment operator where as R-values only appear on the right.

So x is an L-value because it can appear on the left as we’ve just seen, or on the right like this:
y = x;

However, constants like 1 are R-values because 1 could appear on the right, but 1 = x; is invalid.

Pointers

POINTERS are VARIABLES that store the memory address of other variables.

Suppose we had an integer variable, x. We know how to get the address of x using &, but how do we store the hex value returned by &x ?

This is where pointers come into play. A pointer is a variable, so it is declared just like a variable. The only difference is that pointer variables must have the DEREFERENCE OPERATOR, *, before its name.

Don’t confuse this with the multiplication operator though – multiply takes two operands (e.g. x*y), dereference only takes one (e.g. *x).

The data type of a pointer must match the data type of the variable it points to.

Let’s look at declaring and initializing pointers…

int x;

float y;

int *pointer_to_x;

pointer_to_x = &x;

float *pointer_to_y = &y;

/*a simpler way*/

Finally, *pointer_to_x = &x; causes a compilation error, so be careful with the way you declare and initialize your pointers.

char * is somewhat special, and will be looked at in the string section.

Warning

You compiler might complain if you try and declare variables after creating pointers, so it’s best if you declare all your variables at the beginning of main, rather than “on the fly” e.g. halfway through main.

Accessing Variable Values Using Pointers

Now that you have a pointer that points to a variable, how can we retrieve the value it’s pointing to?

Answer: you can access the variable’s value using the dereference operator. Here’s an example:

#include <stdio.h>

int main() {

int x = 12;

int *ptr = &x;

printf(“Address of x: 0x%p\n”, ptr);

printf(“Address of x: 0x%x\n”, &x);

printf(“Address of ptr: 0x%x\n”, &ptr);

printf(“Value of x: %d\n”, *ptr);

return 0;

}

Output:

The first 2 printf statements demonstrates that the address of x is stored in the pointer variable, ptr. Notice how %p returns a full 8 digit hex value in uppercase – maybe I should’ve used %X for the address of x for clarity.

The 3rd printf demonstrates that ptr itself has a place in the memory, which shows it’s a variable.

The final printf uses the dereference operator to extract the value pointed to by ptr, like this: *ptr.

Pointers and Arrays

When I first learnt pointers, I kept thinking: “Why should I use pointers?!!”. Looking at my previous example, I could’ve simplify things a little by not using pointers.

Pointers are useful when it comes to arrays.

One less obvious fact is that the name of an array is a pointer, simply because the name points to the first element of that array.

Try and picture this: when you initialize an array (of size 10, lets say), the computer picks a row of 10 CONSECUTIVE unused memory slots and stores the values in them.

The name of the array refers to the base of the array, that is, the very first memory slot of that array (which holds the first element).

So if the name is a pointer, we should be able to extract the first element using the dereference operator. In other words, *nameOfArray should return the value of nameOfArray[0].

#include <stdio.h>

int main() {

int x[10] = {0,1,2,3,4,5,6,7,8,9};

printf(“Address of x[0]: 0x%p\n”, &x[0]);

printf(“Address of x: 0x%p\n”, x);

printf(“Value of x[0]: %d\n”, x[0]);

printf(“Value of x[0]: %d\n”, *x);

return 0;

}

Output:

So the name of the array points to the first element, as assumed.

Pointer Arithmetic

Once we’ve created a pointer that points to a certain variable, we can either reassign it another variable’s address, or we can move it around by performing POINTER ARITHMETIC.

Suppose we had an int pointer, ptr. If we say ptr++, ++ptr or ptr+=1, we’re actually moving the pointer forward by 2 bytes (i.e. the size of its data type). So it’ll point somewhere else in the computer’s memory.

Similarly, ptr–, –ptr and ptr-=1 will move the int pointer “back” 2 bytes.

And you’re not restricted to move in steps of 1 either: ptr+=n will move it “forward” by n*2 bytes, (assuming ptr is an int pointer).

The larger the data type, the larger the step size. So if ptr was a double pointer, ptr-=3 will move it “back” by 3*8 = 24 bytes.

Warning

The arithmetic assignment operators you can use with pointers are += and -=

ptr*=2 and ptr/=2 cannot be used!

Passing Pointers to Functions

Recall from a previous tutorial that you can pass arrays to functions. The array isn’t actually passed to the function – just the array’s address, or more precisely, a pointer to the array. This is known as PASS BY REFERENCE. The name of an array is a pointer to the first element.

This example is similar to a prevoius example in the Passing Arrays to Functions section, but notice the new function header and the pointer arithmetic inside the function.

Notice that when you pass an int * to a function, there should be an int * declared variable in your function header. The basic trick is to remove the [] and add a * before the array name. See the alternative version back in the Passing Arrays to Functions section for a comparison.

Inside the for loop, the dereference operator is used to fetch the value pointed to and added onto sum. At the end of each loop iteration, the fiveNumbers pointer is incremented to point to the next value.

#include <stdio.h>

void half(int *number); /* declare function */

void half2(int number); /* declare function */

int main() {

int i = 8;

int *ptr = &i; /* create a pointer to i */

half(ptr);

printf(“The value of i is %d\n”, i);

half(&i);

printf(“The value of i is %d\n”, i);

half2(i);

printf(“The value of i is %d\n”, i);

return 0;

}

void half(int *number) {

*number = *number/2;

}

void half2(int number) {

number = number/2;

}

Output:

You can see that passing ptr to half modifies i. Passing &i to half halves i again – remember that ptr simply stores the address of i, i.e. &i.

Passing i to half2 (note the difference between half and half2) has no effect on i when program flow returns to main.

Introduction, Characteristics of Computers – Speed, Accuracy, D <!– @page { size: 8.5in 11in; margin: 0.79in } P { margin-bottom: 0.08in } H2 { margin-bottom: 0.08in } H2.cjk { font-family: “DejaVu Sans” } H2.ctl { font-family: “DejaVu Sans” } –>

Handling of Character Strings-

A string is an array of characters. Strings must have a 0 or null character after the last character to show where the string ends. The null character is not included in the string.

There are 2 ways of using strings. The first is with a character array and the second is with a string pointer.

A character array is declared in the same way as a normal array.

char ca[10];

You must set the value of each individual element of the array to the character you want and you must make the last character a 0. Remember to use %s when printing the string.

char ca[10];
ca[0] = 'H';
ca[1] = 'e';
ca[2] = 'l';
ca[3] = 'l';
ca[4] = 'o';
ca[5] = 0;
printf("%s",ca);

String pointers are declared as a pointer to a char.

char *sp;

When you assign a value to the string pointer it will automatically put the 0 in for you unlike character arrays.

char *sp;
sp = "Hello";
printf("%s",sp);

You can read a string into only a character array using scanf and not a string pointer. If you want to read into a string pointer then you must make it point to a character array.

char ca[10],*sp;
scanf("%s",ca);
sp = ca;
scanf("%s",sp);

Declaration & Initialization of Strings

char string[24]=”mech”

String standard functions

String handling functions

The strings.h header file has some useful functions for working with strings. Here are some of the functions you will use most often:

strcpy(destination,source)
You can’t just use string1 = string2 in C. You have to use the strcpy function to copy one string to another. strcpy copies the source string to the destination string.

s1 = "abc";
s2 = "xyz";
strcpy(s1,s2);
// s1 = “xyz”

strcat(destination,source)
Joins the destination and source strings and puts the joined string into the destination string.

s1 = "abc";
s2 = "xyz";
strcat(s1,s2);
// s1 = “abcxyz”

strcmp(first,second)
Compares the first and second strings. If the first string is greater than the second one then a number higher than 0 is returned. If the first string is less than the second then a number lower than 0 is returned. If the strings are equal then 0 is returned.

s1 = "abc";
s2 = "abc";
i = strcmp(s1,s2);
// i = 0

strlen(string)
Returns the amount of characters in a string.

s = "abcde";
i = strlen(s);
// i = 5

User defined functions

Defining and declaring function prototypes,

the return statement

Functions are sub-programs. You have already been using a function which is the main function.

You must always declare a function before the function that calls it. The main function will be calling our function so we will put ours above main.

First put its return value such as int or char. If you don’t want a return value then use void. After that give it a unique name and put a set of brackets after that. You then put the set of curly brackets which will have the sub-program between them. We will call our function Hello because it will simply print the word Hello on the screen.

#include<stdio.h>
void Hello()
{
printf("Hello\n");
}

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

Parameters

Parameters are values that are given to a function so that it can perform calculations with them. The “Hello\n” which we used in the Hello function is a parameter which has been passed to the printf function.

You need to declare variables inside the parameter brackets to store the values of the parameters that are passed to the function. Here is an Add function which adds the 2 parameters together and then returns the result.

#include<stdio.h>
int Add(int a,int b)
{
return a + b;
}
int main()
{
int answer;
answer = Add(5,7);
return 0;
}

You can pass the address of a variable to a function so that a copy isn’t made. For this you need a pointer.

#include<stdio.h>

int Add(int *a,int *b)
{
return *a + *b;
}
int main()
{
int answer;
int num1 = 5;
int num2 = 7;
answer = Add(&num1,&num2);
printf("%d\n",answer);
return 0;s
}

Introduction

Your computer’s memory is a resource – it can run out. The memory usage for program data can increase or decrease as your program runs.

Up until this point, the memory allocation for your program has been handled automatically when compiling. However, sometimes the computer doesn’t know how much memory to set aside (for example, when you have an unsized array).

The following functions give you the power to dynamically allocate memory for your variables at RUN-TIME (whilst the program is running). For the past tutorials, memory was allocated when the program was compiled (i.e. COMPILE-TIME).

To use the four functions discussed in this section, you must include the stdlib.h header file.

Introduction

A function can be thought of as a mini-program, where a group of statements are executed when the function is called.

A function is CALLED (or INVOKED) when you need to branch off from the program flow and execute the group of statements within that function. Once the statements in the function are executed, program flow resumes from the place where you called your function.

You’ve already encountered a few functions: main, printf and scanf.

The main function is special, in the way that it’s called automatically when the program starts.

In C, and other programming languages, you can create your own functions.

A Typical Function

Functions have 5 main features:

1. The DATA TYPE is the data type of the RETURN VALUE of the function.
2. The NAME is required as an identifier to the function, so that the computer knows which function is called. Naming of functions follows the same set of rules as the naming of variables.
3. Functions can take ARGUMENTS – a function might need extra information for it to work. Arguments are optional.
4. The function BODY is surrounded by curly brackets and contains the statements of the function.
5. The RETURN VALUE is the value that is passed back to the main program. Functions exit whenever you return a value.

This is what a function definition might look like:

int squareNumber(int a)

{

int b = a*a;

return b;

}

The variables within the squareNumber function are LOCAL VARIABLES – when the function exits, variables a and b are deleted from memory.

int squareNumber(int a) is also known as the FUNCTION HEADER.

Declaring and Defining Functions

Before you use a function you must the function before the main function.

Like with variables, this involves writing the data type, then the function name. Unlike variables, you must also decalre all the arguments that the function will use.

The function declaration is a single statement consisting of the function header – don’t forget the semi colon at the end!

Here is an example with a function declaraion:

#include <stdio.h>

void printAverage(int x, int y, int z);

/* the function declaration */

int main() {

int a, b, c;

printf(“Enter 3 integers separated by spaces: “);

scanf(“%d %d %d”, &a, &b, &c);

printAverage(a, b, c); /* the function call */

return 0; /* exit main function */

}

void printAverage(int x, int y, int z) {

/* the function definition */

float average = (float) (x + y + z) / 3;

/* coersion in practice! */

printf(“The average value of %d, %d and %d is %f\n”,

x, y, z, average);

}

It’s common practice to place the function definition underneath main – if you’re editing main most of the time, you wouldn’t want to scroll too far down the page to get to it!

You can put the function definition above it if you wanted. In that case you would not need the the semi-colon at the end of the function header as we would be declaring and defining it at the same time.

But if you place it underneath main, make sure you put the function declaration above main – see the example. This is because the computer won’t know if the function exists if you call it without it being declared in the first place. It’s the same with variables: you can’t assign anything to x unless you’ve declared x beforehand.

Notice that in the function call I had to pass three arguments to match the three arguments in the function definition. Also, the variable names in the function’s argument section didn’t have to match the variable names in the function call. The most important thing is that the data types match.

Functions That Call Themselves

#include <stdio.h>

int factorial(int x);

int main() {

int a, b=1, temp;

printf(“Enter an integer: “);

scanf(“%d”, &a);

printf(“\n%d factorial is %d\n\n”, a, factorial(a));

printf(“Enter another integer: “);

scanf(“%d”, &a);

temp = a;

for( ; a>0 ; a–) {

b*=a;

}

printf(“\n%d factorial is %d\n”, temp, b);

return 0;

}

int factorial(int x)

{

/* n factorial, (or n!) is 1*2*3* … *n */

if(x!=0) {

return (x*factorial(x-1));

}

else

{

return 1;

}

}

A function that calls itself is said to be a RECURSIVE function.

<!– @page { size: 8.5in 11in; margin: 0.79in } P { margin-bottom: 0.08in } –>

  • Declare the Function: We do this with a function prototype, which declares the function so that the compiler knows about it. This declaration provides a complete description of the function interface. Function prototypes usually precede main. They tell the compiler and us what a function will do, but not HOW it will do it.

  • Write the Function Definition: The definition consists of a body and a header. The header is virtually a repeat of the prototype. The body contains the declaration and the executable statements for the function.

  • Write the Call(s) to the Function: These calls cause the function to execute and return values (if there are any to be returned). While there is one prototype and one definition per function, there may be many calls, with different arguments.

Recursive function calls can be less efficient than a loop, and I don’t personally use them.

There’s nothing new in the last example for me to explain. Later, I will show you how to define your functions in file different to the one where main sits.

Knowing When Your Variables Are Accessible

All constants and variables have scope. In other words, the values they hold are accessible in some parts of the program, where as in other parts, they don’t appear to exist.

There are 4 types of scope: block, function, file and program scope. Each one has its own level of scope.

Block Scope

Recall that a statement block is a group of statements enclosed within an opening and closing curly brackets: {}.

Now, if you declare a variable within a statement block, when the program exits the block, the variable will cease to exist.

This type of variable, is said to have BLOCK SCOPE, and is also known as a LOCAL VARIABLE.

You’ve already used local variables before – when you defined your own functions, for instance. Outside of the function definition, the variable would not be visible, as shown in this example:

There are times when your program contains a nested block, like a for loop inside main(). If you were to declare and initialize a variable x outside the loop and then declare and initialize another variable called x inside the loop, they will occupy up different memory slots and are considered as different variables. The effect can be shown in this example:

Function Scope

This type of scope only applies to goto label names. You can’t have the same label name inside a function. However, you can have the same label name in different functions like this:

Program Scope

If you want to avoid passing arguments to your functions you can declare your variables outside any function blocks. Such variables are sometimes known as GLOBAL VARIABLES. Their value can be accessed from anywhere within the ENTIRE program. Take this example:

File Scope

FILE SCOPE is when a variable is only accessible until the end of the file.

A variable with file scope is a global variable declared with the the static keyword before the data type, like this:

static int x = 15;

This makes it impossible for x to be accessible by other files, other than the one it’s declared and initialized in.

This is useful for when you come to write your own header files and function prototypes as it can prevent compilation errors and potential bugs.

Let’s recap:

1.

Variables with BLOCK SCOPE (variables declared in a block, i.e. local variables) are the least accessible, as they are visible between an opening curly bracket and a closing one.

2.

Variables with FUNCTION SCOPE (goto labels in this case) are the next least accessible, as they are visible in a whole function.

3.

Variables with FILE SCOPE(global variables with the static specifier) are the second most accessible, as they are visible in the whole file.

4.

Finally, variables with PROGRAM SCOPE (variables declared outside any blocks, i.e. global variables) are always accessible throughout the program.

What is a struct?

A struct (short for STRUCTURE), is a collection of variables of different types. Structures are sometimes referred to as ABSTRACT DATA TYPES, or ADTs for short.

We already know how to store a group of variables of the same type using arrays.

Variables in a struct are called MEMBERS or FIELDS, and are accessed by their name.

Variables in an array are called ELEMENTS, and are accessed using square brackets an an index.

Declaring a Structure

Declaring a struct requires the struct keyword, followed by a name. Then you declare your collection of variables between a pair of curly brackets. For example:

struct human {

char *name;

int age;

float height;

};
/* don’t forget this

semi colon!!!! */

It’s best to declare your struct before main.

human is now a structure type, with three fields: name, expressed as a string, an integer age and a floating point height.

You can put whatever data types you want. And you’re not limited to normal variables either – arrays and pointers can also go into a struct, though, you must specify an array size.

You can NOT use the assignment operator with the struct declaration.

NOTE: The size of a struct is the sum of the sizes of all the variables it holds.

Declaring Structure Variables

Like with enum, you can insert a list of variables after the end bracket like this:

struct album {

char *name;

char *artist;

int numTracks;

} CD1, CD2, CD3;

This declares three variables of the struct album type.

But if album was declared outside main, the three variables will be global variables.

So instead, you can write this inside main:

struct album CD1, CD2, CD3;

Or better still, declare your struct and write:

typedef struct album Album;

… then inside main:

Album CD1, CD2, CD3;

Try and group all your typedef statements outside main – it makes the code look neater and easier to maintain.

Initializing Structure Variables

Now that you know how to declare structure variables, there are two ways to initialize them: all the fields in one statement, or one field at a time.

To initialize all fields in one statement, you declare your variable as usual, but assign it a list of variables enclosed in brackets, like this:

struct human TR = {“Tony”, 12, 1.5};

This is similar to the method of initializing arrays.

Now the struct human variable, TR has all three fields initialized: the name field holds the string, “Tony”, the age field holds the integer, 12, and the height is 1.5.

To reference an individual field, you use the DOT OPERATOR to separate the struct variable name and the field name.

You can use the dot operator to initialize each field individually:

struct human TR;

TR.name = “Tony”;

TR.age = 12;

TR.height = 1.5;

To access each field, use the dot operator again.

For example, TR.age will return 12.

Advantages of char *name Over char name[50]

When I first encountered structs I used a sized char array to store strings.

Suppose I redefine human:

struct human {

char name[50];

int age;

float height;

};

The first disadvantage, is that the name array must have a size big enough to store any string I was going to use.

Secondly, the only (obvious) way to initialize a string field, is to do it all at once:

struct human TR = {“Tony”, 12, 1.5};

TR.name = “Tony” won’t work, simply because the only way of assigning a string into an array is when you declare an array: char name[5] = “Tony”; Recall that TR.name is actually a char pointer, but it’s an R-value in this case. In other words, assigning a value into it wouldn’t work, as it wasn’t declared as a char *. But…

TR.name[0] = ‘T’;

TR.name[1] = ‘o’;

TR.name[2] = ‘n’;

TR.name[3] = ‘y’;

TR.name[4] = ”;

… works because the elements of the name array are L-values.

If human was defined with char *name, you could use TR.name = “Tony”; because pointers are L-values: remember that strings are considered to be of type char * as well.

Arrays of Structure Variables

Like with the usual data types, you can store a group of similar typed variables in an array.

The method of declaring an array is the same as before, but initializing your elements isn’t as simple as first thought…

#include <stdio.h>

typedef struct robot ROBOT;

struct robot {

char *name;

int energy;

};

int main()

{

int i;

ROBOT robots[3];

robots[0].name = “Lunar Lee”;

robots[0].energy = 50;

robots[1].name = “Planetary Pete”;

robots[1].energy = 20;

robots[2].name = “Martian Matt”;

robots[2].energy = 30;

/* robots[0] = {“Lunar Lee”, 50}; WON’T WORK,

BUT HERE’S ANOTHER WAY…

ROBOT robots[3] = { {“Lunar Lee”, 50},

{“Planetary Pete”, 20},

{“Martian Matt”, 30} }; */

for(i=0 ; i<3 ; i++) {

printf(“Robot %d is called %s “, i, robots[i].name);

printf(“and has %d units of energy.\n”, robots[i].energy);

}

return 0;

}

There is a quicker way of initialization, as shown in the commented section. It involves initializing the entire array all at once. Notice how I separated each array element with a line break for clarity. Also note that a group of fields must be enclosed in brackets as well: {“Lunar Lee”, 50}, for example.

Pointing to Structures and Using the Arrow Operator ->

Like with arrays, you can create pointers to structures. This time, the pointer stores the memory address of a structure variable.

Declaring you pointer follows along the same lines as with arrays, for example, if user was of type HUMAN (where HUMAN is struct human):

HUMAN *human_ptr = &user;

Or:

HUMAN *human_ptr;
human_ptr = &user;

– Both of these would do the trick. However, make sure you’ve declared all your program variables before initializing pointers, else you’d encounter problems later on!

Your compiler might complain if you try and declare variables after creating pointers, so it’s best if you declare all your variables at the beginning of main, rather than “on the fly” e.g. halfway through main.

Now that you’ve created a pointer, you now access fields using the arrow operator, which is made up of two characters: a hyphen, then the greater than sign: ->. This replaces the dot operator, but other than that, accessing structure fields is similar:

human_ptr->name = “Martin”;

Is the equivalent of:

user.name = “Martin”;

Here’s the last example rewritten using pointers:

Passing Structures to Functions

This is similar to passing arrays to functions.

In the function declaration you need to specify the structure’s type, then a name and any other arguments.

Passing pointers is a better way, but for demonstration purposes, here’s a function that expects a ROBOT variable and displays some info:

#include <stdio.h>

typedef struct robot ROBOT;

struct robot {

char *name;

int energy;

int IQ;

float velocity;

};

void info(ROBOT r); /* declare function */

int main() {

ROBOT r1 = {“Earthling Ed”, 100, 231, 4.1}; /* initialize 2 ROBOTs */

ROBOT r2 = {“Toxic Tom”, 150, 254, 2.5};

info(r1);

info(r2);

return 0;

}

void info(ROBOT r) {

printf(“%s has %d units of energy, an IQ of %d…\n”,

r.name, r.energy, r.IQ);

printf(“… and a velocity of %0.1f metres per second.\n”,

r.velocity);

}

Output:

Notice how I moved the function declaration below the typedef statement, since I used the defined type, ROBOT, in the function’s argument section.

info returns nothing, hence the void data type, and expects a ROBOT variable. r is a local variable that is created whenever info is called.

The %0.1f format specifier in the second printf displays the velocity correct to 1 decimal place. The zero is the minimum field width (the least number of spaces the number will occupy when displayed on screen).

Structures Within Structures

You can have fields of any data type in a structure, as well as pointers and arrays AND other structures.

You must create a struct before you use it in another struct, but declaring the field is similar to declaring an array.

#include <stdio.h>

typedef struct weapon WEAPON;

typedef struct robot ROBOT;

struct weapon {

int ammo;

char *name;

int damage;

};

struct robot {

WEAPON weapon1; /* struct within a struct */

char *name;

int energy;

};

int main() {

ROBOT boss = { {100, /* boss.weapon1.ammo */

“Laser Gun”, /* boss.weapon1.name */

25}, /* boss.weapon1.damage */

“Krypton Kathy”, /* boss.name */

250}; /* boss.energy */

ROBOT *ptr1;

WEAPON *ptr2;

/*boss.weapon1.ammo = 100; alternative initialization –

notice I had to put:

boss.weapon1.name = “Laser Gun”;

this is AFTER declaring the 2 pointers above

boss.weapon1.damage = 25;

boss.name = “Krypton Kathy”;

boss.energy = 250;*/

ptr1 = &boss;

ptr2 = &boss.weapon1;

printf(“You have encountered %s.\n”, ptr1->name);

printf(“She has %d units of energy.\n”, ptr1->energy);

printf(“Her weapon is the deadly %s.\n”, ptr2->name);

printf(“Each hit takes up to %d units of energy off you.\n”,

ptr2->damage);

printf(“She has %d shots left.\n”, ptr1->weapon1.ammo);

printf(“You have 10 units of energy left. “);

printf(“Situation critical.\n Abort mission.\n”);

return 0;

}

Output:

In the definition of struct robot, you can see that I’ve used a struct weapon variable as one of the fields. struct weapon must been defined before struct robot, otherwise your compiler will complain about an undefined struct.

Inside main, I’ve declared and initialized a ROBOT variable. Look closely and you’ll see that there are 2 brackets surrounding the first three items – this is because the first three items belong to the struct weapon field.

After that, I declared two pointers – one that points to the boss and the other points to the weapon1 field of boss.

The first four printf statements make use of ptr1 and ptr2 to access certain fields, but in the fifth, notice that it’s ptr1->weapon1.ammo and not ptr1->weapon1->ammo. This is because weapon1 is not a pointer to a struct weapon, but an actual struct weapon field, hence the dot operator.

What is a union?

A union, is a collection of variables of different types, just like a structure. However, with unions, you can only store information in one field at any one time.

You can picture a union as like a chunk of memory that is used to store variables of different types. Once a new value is assigned to a field, the existing data is wiped over with the new data.

Declaring a union

Declaring a union is exactly the same as declaring a struct, except you use the union keyword:

union human {

char *name;

int age;

float height;

}; /* don’t forget this semi colon!!!! */

Once again, you can use a typedef statement to simply the declaration of union variables.

The size of an union is the size of its largest field. This is because a sufficient number of bytes must be reserved for the largest sized field.

Initializing Unions

Now, this is where things get a little different to structures. Like I said before, with a union, fields share the same memory space, so fresh data replaces any existing data. This example demonstrates what happens if you initialize all the data for a union variable, all at once:

#include <stdio.h>

typedef struct robot1 ROBOT1;

typedef union robot2 ROBOT2;

struct robot1 {

int ammo;

int energy;

};

union robot2 {

int ammo;

int energy;

};

int main() {

ROBOT1 red = {10,200};

/* ROBOT2 blue = {15,100}; DOESN’T WORK WITH UNIONS */

ROBOT2 blue;

blue.ammo = 15;

blue.energy = 100;

printf(“The red robot has %d ammo “, red.ammo);

printf(“and %d units of energy.\n\n”, red.energy);

printf(“The blue robot has %d ammo “, blue.ammo);

printf(“and %d units of energy\n.”, blue.energy);

return 0;

}

Output:

First notice how similar the declaration of a union is to a struct.

Things get a little different inside main. You can’t initialize fields of a union variable all at once – try removing the correct initialization above and see what your compiler says. So I initialized each field separately…

The first printf statement displays the expected for the struct version of our robot.

The second printf shows you that the program has overwritten data in the ammo field with data of the energy field – this is how unions work. All fields share the same address, where as with structs, each field has its own address.

This example is similar to the last, except I used printf before initializing the energy field of the union:

#include <stdio.h>

typedef struct robot1 ROBOT1;

typedef union robot2 ROBOT2;

struct robot1 {

int ammo;

int energy;

};

union robot2 {

int ammo;

int energy;

};

int main() {

ROBOT1 red = {10,200};

ROBOT2 blue;

printf(“The red robot has %d ammo “, red.ammo);

printf(“and %d units of energy.\n\n”, red.energy);

blue.ammo = 15;

printf(“The blue robot has %d ammo”, blue.ammo);

blue.energy = 100;

printf(” and %d units of energy.”, blue.energy);

return 0;

}

Data in the energy field has still overwritten the ammo field though – rearranging the printfs has changed made the outcome different from that of the last example.

Arrays of Union Variables

The concept is the same as that of structs. However, because of the problem of new data overwriting existing data in the other fields, the struct version of the following example won’t work if you simply replace all instances of struct with union.

#include <stdio.h>

typedef union robot ROBOT;

union robot {

char *name;

int energy;

};

int main() {

int i;

ROBOT robots[3];

robots[0].name = “Lunar Lee”;

robots[0].energy = 50;

robots[1].name = “Planetary Pete”;

robots[1].energy = 20;

robots[2].name = “Martian Matt”;

robots[2].energy = 30;

for(i=0 ; i<3 ; i++) {

/*printf(“Robot %d is called %s “, i, robots[i].name);*/

printf(“and has %d units of energy.\n”, robots[i].energy);

}

return 0;

}

The reason why I commented out the printf that displays the name is because I initialized everything at once. As a consequence, by the time the program reaches the for loop the union holds an int variable, rather than a char *. In general, my program crashes whenever an int is passed to the string format specifier, %s – other compilers might produce a different result.

Unions Inside Structures

I can’t see any obvioud reasons why one might use unions, but here’s a case when they could be useful. Suppose we want a field of a structure to contain a string or an integer, depending on what the user specifies. Take this example:

#include <stdio.h>

struct choice {

union {

char *name;

int age;

};

int number;

};

Final Remarks on Unions

Firstly, nested unions are possibly, but are a little pointless. One union has the same memory space for all fields. If one of your fields is a union, that union would also let its fields share memory space – the same memory space reserved for the first union!!

Pointing to unions, passing unions to functions and passing pointers to unions to function are all done in the same way as that of structs. To find out more, do some searching on the web🙂

The C preprocessor is a program that is executed before the source code is compiled.

C preprocessor commands are called DIRECTIVES, and begin with a pound / hash symbol (#). No white space should appear before the #, and a semi colon is NOT required at the end.

You’ve already seen a directive: #include

This takes the specified file, and pastes its contents into the place where you put #include before the source code is compiled. So when you use printf, stdio.h is required so that the compiler knows what printf is.

#include

If a line starts with a hash, denoted by #, it tells the compiler that a command should be sent to the C PREPROCESSOR. The C preprocessor is a program that is run before compilation takes place (hence the name). #include is one of the many C preprocessor commands you’ll use.

Basically, when the preprocessor finds #include it looks for the file specified and replaces #include with the contents of that file. In a way, this makes the code more readable and easier to maintain if you needed to use common library functions. More preprocessor commands in the later sections…..

Header Files

Header files have the extension .h and the full filename follows from the #include directive.

They contain declarations to certain functions that you may or may not have used in your program.

For example, the stdio.h file is required if you have used functions like printf and scanf in your program. More about these two functions in the Standard Input and Output section.

There are two ways to include a header file:
#include “stdio.h” and
#include <stdio.h>

If you use the double quote marks, it means that the directory you’re currently in, will be searched for first for the header file, before any other directories are searched.

If you use the angled brackets, directories other than the one you’re currently in, will be searched for the header file. Usually this will be the default directory for header files specified in your compiler, so you’ll probably be using square brackets all the time.

#define

#define allows you to make text substitutions before compiling the program. Here’s an example:

#define MAX 10

Before compilation, if the C preprocessor finds MAX as one word (so words like MAXIMUM will not be affected), in the source code, it replaces it with the number 10. If MAX was part of a string (for example, between the quote marks of printf), the preprocessor will leave it alone.

You can call the MACRO DEFINITION anything you want, as long as it doesn’t contain special characters or spaces and it cannot start with a number. I tend to use uppercase and underscore characters. You can define strings as well:

#define WEBSITE_NAME “Eddie’s Basic Guide to C”

– Every time the preprocessor sees WEBSITE_NAME it will replace it with “Eddie’s Basic Guide to C”

#define commands must be placed before the main function. The # symbol must be the first character of the line in the source code.

#include <stdio.h>

#define MIN 0 /* #defines */

#define MAX 10

#define TRUE 1

#define FALSE 0

The program will loop until you enter a number between 0 and 10.

By the time the compiler receives the program, it won’t see words like MIN, MAX, TRUE or FALSE in the source code. Instead, it’ll see the numbers 0, 10, 1 and 0 respectively.

#undef and Macro Functions

If you’ve created a macro definition, you can use #undef to remove it. This means the preprocessor will no longer make anymore text substitutions associated with that word. Also, to change a definition, you must use #undef to undefine it, then use #define to redefine it.

You can use #define to create your own MACRO FUNCTIONS. These are useful when the function is relatively small.

For example:

#define SQR(a) (a*a)

Now if you write SQR(3) in your program, the preprocessor will replace it with (3*3) in your program, NOT 9.

Be careful with your brackets, as this example demonstrates:

#include <stdio.h>

#define MAX(a,b) (a>b ? a : b) /* a “function” */

#define DIFF1 4-7

#define DIFF2 (4-7)

#define NUMBER 10

#undef NUMBER

/* now undefine NUMBER so that we can give it a different value */

#define NUMBER 7

printf(” now I live at number %d.\n”, NUMBER);

return 0;

}

Output:

Let’s look at the printf statements:

The compiler will see the first one as:

printf(“Out of %d and %d, %d is the bigger number.\n”,

a, b, (a>b ? a : b));

Since we initialized a and b beforehand, it’ll work out if a is greater than b, if so, return a from the expression, else return b.

The compiler will see the next two printfs as:

printf(“DIFF1 = 4-7. DIFF1 times 10 equals %d.\n”, 4-7*10);
printf(“DIFF2 = (4-7). DIFF2 times 10 equals %d.\n”, (4-7)*10);

Notice how the preprocessor leaves DIFF1 and DIFF2 alone inside the string of printf. Looking at the above lines, you can clearly see why the top printf prints out -66, where as the bottom did the obvious and printed 30 – macro definitions are just text substitutions!

The next printf is seen as : printf(“I live at number %d.\n”, 10);

After that, NUMBER is undefined, then redefined, so the next printf will look like:

printf(” now I live at number %d.\n”, 7);

#ifdef, #ifndef and #endif

When you come to write big programs, sometimes you’ll have to go through a process called DEBUGGING, which involves reading through your program, and trying to find out what’s causing your program to go wrong.

One common method for debugging is to comment out sections of code to find that “bug”. But what if there are comment dotted around your source code? That’s when #ifdef and #ifndef come into play. If you try nesting your comments, you’re going to get a compilation error.

In the case of #ifdef, if the macro definition that follows immediately is defined with #define, the following code from that directive to the #endif directive will be considered as part of the program and will be compiled.

With #ifndef, it’s the other way round, i.e. if there isn’t a definition, the code up to the #endif directive will be considered as part of the program and will be compiled.

Example:

#include <stdio.h>

#define WORD1

/* you don’t have to put an expression after the defined word */

int main()

{

#ifdef WORD1

printf(“1: WORD1 is defined so this bit is compiled.\n”);

#endif

#ifndef WORD2

printf(“2: WORD2 is not defined so this bit is compiled.\n”);

#endif

return 0;

}

Output:

What is a Header File?

Header files contain declarations to functions and variables and have a .h extension. Examples of header files include stdio.h, string.h and strlib.h.

stdio.h looks horrendous in Notepad, so here is an example of a simple header file:

#ifndef EXAMPLE_H

#define EXAMPLE_H

#endif

I called this example.h and will be using it later on by writing #include “example.h” in the source file of the main program.

The functions are defined in a separate source file, so you’ll need to place the extern keyword before the function declaration.

If the header was included the first time, EXAMPLE_H won’t be defined, so the file’s contents are copied and compiled. However, I’ve defined EXAMPLE_H in the second line so if I accidentally included the header file a second time, #ifndef EXAMPLE_H isn’t true, so the contents of the header file are not copied and compiled a second time. I ended the header file with #endif.

Introduction, Characteristics of Computers – Speed, Accuracy, D <!– @page { size: 8.5in 11in; margin: 0.79in } P { margin-bottom: 0.08in } –>

Preprocessor Directives

#define,

The #define directive substitutes token-string for all subsequent occurrences of an identifier in the source file. The identifier is replaced only when it forms a token. sFor instance, identifier is not replaced if it appears in a comment, within a string, or as part of a longer identifier.

A #define without a token-string removes occurrences of identifier from the source file. The identifier remains defined and can be tested using the #if defined and #ifdef directives.

example

#define max 10

#include,

ou can organize constant and macro definitions into include files and then use #include directives to add these definitions to any source file. Include files are also useful for incorporating declarations of external variables and complex data types. You need to define and name the types only once in an include file created for that purpose.

The path-spec is a filename optionally preceded by a directory specification. The filename must name an existing file. The syntax of the path-spec depends on the operating system on which the program is compiled.

example

#include <stdio.h>

#ifndef,

The #ifdef and #ifndef Directives

The #ifdef and #ifndef directives perform the same task as the #if directive when it is used with defined( identifier ).

#ifdef identifier
#ifndef identifier

// equivalent to
#if defined identifier
#if !defined identifier

You can use the #ifdef and #ifndef directives anywhere #if can be used. The #ifdef identifier statement is equivalent to #if 1 when identifier has been defined, and it is equivalent to #if 0 when identifier has not been defined or has been undefined with the #undef directive. These directives check only for the presence or absence of identifiers defined with #define, not for identifiers declared in the C or C++ source code.

These directives are provided only for compatibility with previous versions of the language. The defined( identifier ) constant expression used with the #if directive is preferred.

The #ifndef directive checks for the opposite of the condition checked by #ifdef. If the identifier has not been defined (or its definition has been removed with #undef), the condition is true (nonzero). Otherwise, the condition is false (0).

The #if, #elif, #else, and #endif Directives

The #if directive, with the #elif, #else, and #endif directives, controls compilation of portions of a source file. If the expression you write (after the #if) has a nonzero value, the line group immediately following the #if directive is retained in the translation unit.

#error,

the error messages include the argument token-string and are currently not subject to macro expansion. These directives are most useful for detecting programmer inconsistencies and violation of constraints during preprocessing. The following example demonstrates error processing during preprocessing:

#line directives, Developing a C program-Guidelines

C Storage Classes

The “storage class” of a variable determines whether the item has a “global” or “local” lifetime. C calls these two lifetimes “static” and “automatic.” An item with a global lifetime exists and has a value throughout the execution of the program. All functions have global lifetimes.

Automatic variables, or variables with local lifetimes, are allocated new storage each time execution control passes to the block in which they are defined. When execution returns, the variables no longer have meaningful values.

C provides the following storage-class specifiers:

Syntax

storage-class-specifier:
auto
register
static
extern
typedef
  1. S. Mohanarangan
    May 5, 2009 at 9:41 PM

    Really a good work. I feel so happy from this site. Thank you Kuttysudha

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: