48622 Mechatronics 1 C programming primer Adapted from a range of materials found at: http://www.le.ac.uk/users/rjm1/cotter (© University of Leicester, 2012) http://www.cs.cf.ac.uk/Dave/C/ (© A. D. Marshall 1994-2005) http://upload.wikimedia.org/wikipedia/commons/0/07/C_Programming.pdf (Public Domain License, Wikibooks, 2012) TABLE OF CONTENTS 1. INTRODUCTION........................................................................................................................... 3 2. WORKFLOW ................................................................................................................................ 3 3. CONCEPTS .................................................................................................................................. 3 3.1. Chapter 1: Program structure, Variable types and I/O on screen ............................................. 3 3.1.1 History of C ....................................................................................................................... 3 3.1.2 The Edit-Compile-Link-Execute Process ............................................................................ 4 3.1.3 Structure of a C program ................................................................................................... 4 3.1.4 Pre-processor directives .................................................................................................... 5 3.1.5 Your first C program .......................................................................................................... 6 3.1.6 Variables and data types ................................................................................................... 6 3.1.7 Basic operators in C .......................................................................................................... 7 3.1.8 Basic input/output operations............................................................................................. 8 3.2. Chapter 2:............................................................................................................................. 11 3.2.1 Conditional statements .................................................................................................... 11 3.2.2 Looping statements ......................................................................................................... 12 3.2.3 Arrays and Strings ........................................................................................................... 14 3.3. Chapter 3:............................................................................................................................. 15 3.3.1 Functions ........................................................................................................................ 15 3.4. Chapter 4:............................................................................................................................. 19 3.4.1 Pointers........................................................................................................................... 19 3.5. Chapter 5:............................................................................................................................. 24 3.5.1 Structures........................................................................................................................ 24 4. EXERCISES ............................................................................................................................... 27 4.1. Chapter 1:............................................................................................................................. 27 4.2. Chapter 2:............................................................................................................................. 28 4.3. Chapter 3:............................................................................................................................. 30 4.4. Chapter 4:............................................................................................................................. 30 4.5. Chapter 5:............................................................................................................................. 31 1. INTRODUCTION During the final Chapters of 48622 Mechatronics 1 we will be working on programming microprocessors. This type of programming – i.e., creating code which can run on a standalone microprocessor – is generally referred to as embedded programming. Embedded system is a generic term for some combination of hardware and software designed to carry out a specific pre-defined task as part of a larger system. Examples of embedded systems could be the controller of a robot, an electronic telephone's core, the microprocessor inside a TV remote control, and many many more. There are two favourite languages to write programs for embedded systems: Assembly and C/C++. They are preferred because they allow the programmer to have complete control of microprocessor operation (in the case of assembly, at single microprocessor operation level, while in the case of C at a slightly higher level of abstraction). Many of the students enrolled in MX1 have a poor knowledge of the C programming language, and even before we can start thinking of programming microprocessor, this deficiency must be addressed. Such is the purpose of this primer document: to cover some essential features of the language throughout a few Chapters of self-guided learning. What you will find in this document is not embedded C. You will learn the basics of the C language and we will build on those basics to develop microprocessor-specific knowledge later in the course. Working with your PC rather than a small chip with only a few inputs and outputs (on-screen words are easier to interpret than jumpy voltages on metal pins) will allow you to "see" the code in action and hopefully learn the basics quickly. For information on how to run a C compiler on your system and run a program after you have written it, refer to the software info guide on UTSonline. As this course component is based on self-learning, I also recommend that students use the forums to share ideas and help each other (solutions to exercises should not be exchanged in the interest of individual learning, but more skilled students can and should share their knowledge of C with those who are beginners in this subject). 2. WORKFLOW The primer is divided into 2 sections: concepts and exercises. Each section has 5 subsections and it is recommended that you go through one subsection each Chapter (read the concepts and carry out the exercises). No exercises are mandatory but they are all recommended so that you can get a minimum amount of programming experience under your belt. 3. CONCEPTS 3.1. Chapter 1: Program structure, Variable types and I/O on screen 3.1.1 History of C C is a general-purpose language which has been closely associated with the UNIX operating system for which it was developed - since the system and most of the programs that run it are written in C. Many of the important ideas of C stem from the language BCPL, developed by Martin Richards. The influence of BCPL on C proceeded indirectly through the language B, which was written by Ken Thompson in 1970 at Bell Labs, for the first UNIX system on a DEC PDP-7. BCPL and B are "typeless" languages whereas C provides a variety of data types. In 1972 Dennis Ritchie at Bell Labs writes C and in 1978 the publication of The C Programming Language by Kernighan & Ritchie caused a revolution in the computing world. In 1983, the American National Standards Institute (ANSI) established a committee to provide a modern, comprehensive definition of C. The resulting definition, the ANSI standard, or "ANSI C", was completed late 1988. A much more detailed (and longer) document on the history of C, for those interested, can be found here. 3.1.2 The Edit-Compile-Link-Execute Process Developing a program in a compiled language such as C requires at least four steps: 1. 2. 3. 4. editing (or writing) the program compiling it linking it executing it Editing You write a computer program using words and symbols that are understandable to human beings. This is the editing part of the development cycle. You type the program directly into a window on the screen and save the resulting text as a separate file. This is often referred to as the source file. The custom is that the text of a C program is stored in a file with the extension .c . Compiling You cannot directly execute the source file. To run on any computer system, the source file must be translated into binary code understandable to the computer's Central Processing Unit (for example, an Intel microprocessor). This process produces an intermediate object file (with the extension .obj in Microsoft systems). Linking The first question that comes to most people's minds is: Why is linking necessary? The main reason is that many compiled languages come with library routines which can be added to your program. These routines are written by the manufacturer of the compiler to perform a variety of tasks, from input/output to complicated mathematical functions. An example of a standard C library is stdio.h, which contains a number of fundamental input/output functions. After linking, the program is transformed into an executable file (extension .exe in Microsoft DOS/Windows systems). Executable files Executable files can be run by the operating system as any other application, simply by typing their names at the command prompt or using the Windows menu. 3.1.3 Structure of a C program All C programs will consist of at least one function, but it is usual (when your experience grows) to write a C program that comprises several functions. The only function that has to be present is the function called main. For more advanced programs the main function will act as a controlling function calling other functions in their turn to do the dirty work! The main function is the first function that is called when your program executes. C makes use of only 32 keywords which combine with the formal syntax to the form the C programming language. Note that all keywords are written in lower case - C, like UNIX, uses upper and lowercase text to mean different things. If you are not sure what to use then always use lowercase text in writing your C programs. A keyword may not be used for any other purposes. For example, you cannot have a variable called main. The layout of C Programs The general form of a C program is as follows: pre-processor directives global declarations f1() { local variables to function 1 ; statements associated with function 1 ; } f2() { local variables to function f2 ; statements associated with function 2 ; } int main() { local variables to function main ; statements associated with function main ; } etc... Note the use of the bracket sets () and {}. () are used in conjunction with function names whereas {} are used as to delimit the C statements that are associated with that function. Also note the semicolon (;), which is used to terminate C statements. C is a free format language and long statements can be continued, without truncation, onto the next line. The semicolon informs the C compiler that the end of the statement has been reached. Free format also means that you can add as many spaces or tabulations as you like to improve the look of your programs. A very common mistake made by everyone, who is new to the C programming language, is to miss off the semicolon. The C compiler will concatenate the various lines of the program together and then tries to understand them - which it will not be able to do. The error message produced by the compiler will relate to a line of you program which could be some distance from the initial mistake. 3.1.4 Pre-processor directives C is a small language with a small set of keywords. Most operations are carried out by calling upon functions, and many useful functions are already available in libraries. It is wise for programmers to check whether a library function is available to perform a task before writing their own version. This will reduce program development time. The library functions have been tested, so they are more likely to be correct than any function which the programmer might write. This will save time when debugging the program. Libraries often come in the form of header files (extension .h) and are referred to the pre-processor with a directive which is common in most C programs: #include <library_name.h> Note the use of the # symbol as the first character of a directive line and the angle brackets around the header name. The angle brackets indicate that the header file is to be looked for on the system path which stores the rest of the C programming environment. Some text books will show the above statement as follows: #include "library_name.h" The double quotes indicate that the current working directory should be searched for the required header file. This will be true when you write your own header files but the standard header files should always have the angle brackets around them. Note: as a notable exception, include directives do not require a semicolon as a line terminator. 3.1.5 Your first C program Below is an example of simple code which implements the ubiquitous "Hello World!" program. All the program does is print the message "Hello World!" on the screen. Note also the use of the construct /* comment text */ for comments (use comments in your programs!). #include <stdio.h> int main() { printf("Hello World\n"); /*prints a greeting to the screen*/ } The first line is the standard start for all C programs - main(). After this comes the program's only instruction enclosed in curly brackets { }. The curly brackets mark the start and end of the list of instructions that make up the program - in this case just one instruction. Note that the curly brackets are on separate lines: this is not required but it is a convention to assist with visualising matching brackets. The printf function prints its argument on the screen (\n is a special character meaning "new line"). Try to write and run this program to ensure you have figured out how to compile and run your code in the programming environment of your choice. 3.1.6 Variables and data types This section deals with local variables. These are variables that are used within the current program unit (or function). In a later section we will looking at global variables - variables that are available to all the program's functions. There are five basic data types associated with variables: • • • • • int - integer: a whole number. float - floating point value: ie a number with a fractional part. double - a double-precision floating point value. char - a single character. void - valueless special purpose type which we will examine closely in later sections. In C it is compulsory, upon creation of a variable, to declare what data type it represents. Note: variable names in C must begin with a letter or a "_" (underscore) character. Integer Number Variables The first type of variable we need to know about is of class type int - short for integer. An int variable can store a value in the range -32768 to +32767. You can think of it as a largish positive or negative whole number: no fractional part is allowed. To declare an int you use the instruction: int variable name; For example: int a; declares that you want to create an int variable called a. Decimal Number Variables As described above, an integer variable has no fractional part. Integer variables tend to be used for counting, whereas real numbers are used in arithmetic. C uses one of two keywords to declare a variable that is to be associated with a decimal number: float and double. They are each offer a different level of precision as outlined below. float A float, or floating point, number has about seven digits of precision and a range of about 1.E-36 to 1.E+36. A float takes four bytes to store. double A double, or double precision, number has about 13 digits of precision and a range of about 1.E-303 to 1.E+303. A double takes eight bytes to store. For example: float total; double sum; Character Variables Unlike other programming languages where the concept of "string" exists, C can only deal with numbers and characters. A character is simply the numeric value corresponding to a particular character. A string will be given by an array of characters. To declare a variable of type character, use the keyword char. - A single character stored in one byte. For example: char c; To assign, or store, a character value in a char data type is easy - a character variable is just a symbol enclosed by single quotes. For example, if c is a char variable you can store the letter A in it using the following C statement: c='A'; Again, notice that you can only store a single character in a char variable. Assignment Statement Once you've declared a variable you can use it. Always remember that attempts to use a variable that has not been defined will cause a compiler error. You can store a value in a variable using: name = value; For example: a=10; The four basic arithmetic operations do not require additional libraries, e.g.: a=a+b; a=a-b; a=a*b; a=a/b; You should be careful with operations. The precision of the result stored in a variable will depend on the data type of the variable. For example int a=10/3; will store the value 3 (as opposed to 3.333..) in variable a. (The integer type does not support decimals therefore the result is truncated). The example above also shows that simultaneous declaration and assignment is allowed in C. 3.1.7 Basic operators in C Arithmetic operators As well as the standard arithmetic operators (+ - * /) found in most languages, C provides some more operators. A notable feature is the increment and decrement operators: ++ and --. For example: x++; is equivalent to x=x+1; z--; is equivalent to z=z-1; (actually, from a computing perspective it is more efficient) C also has a convenient shorthand syntax for writing operations like i=i+3 or x=x*(y + 2) i.e., variable operator = expression; e.g., i+=3; or x*=(y+2); Comparison Operators The equality operator is ==. For inequality C uses !=. Other operators < (less than) , > (greater than), <= (less than or equals), >= (greater than or equals) are as usual. A warning: Beware of using ``='' instead of ``=='', such as writing accidentally if(i = j) ... This is a perfectly LEGAL C statement (syntactically speaking) which copies the value in "j" into "i", and delivers this value, which will then be interpreted as TRUE if j is non-zero. This is unlikely to be the intended program behaviour. Hence the warning. Logical Operators Logical operators are usually used with conditional statements (more on these later). The two basic logical operators are: && for logical AND, || for logical OR. Beware: & and | have a different meaning. They refer to for bitwise AND and OR. Order of operations When multiple operators are used in the same expression confusion about precedence may arise. C follows standard precedence for arithmetic. There are precedence rules for other operators but the best advice (also to improve readability of your code) is to use brackets where appropriate to make the order of operations explicit. 3.1.8 Basic input/output operations A very quick overview The variable assignments you have seen so far are fixed, that is, a=100; stores 100 in the variable a each time you run the program, no matter what you do. Without some sort of input command every program would produce exactly the same result every time it was run. In practice, of course, we need programs to do different jobs each time they are run. There are a number of different C input commands, the most basic of which is the scanf command. To read a single integer value into the variable called a you would use: scanf("%d",&a); For the moment don't worry about what the %d or the &a means - concentrate on the difference between this and a=100;. When the program reaches the scanf statement, it pauses to give the user time to type something on the keyboard and continues only when <Enter> is pressed to signal that the value has been entered. Then the program continues with the new value stored in a. In this way, each time the program is run the user gets a chance to type in a different value to the variable and the program also gets the chance to produce a different result! A basic and useful function for output is printf, the one we have already used to print "Hello World". This can print the current value of a variable. To display the value stored in a you would use: printf("The value stored in a is %d",a); The %d, both in the case of scanf and printf, informs the compiler that the value being read in, or printed out, is a decimal integer - that is, a few digits but no decimal point. Note: the scanf function does not prompt for an input. You should get in the habit of always using a printf function, informing the user of the program what they should type, before a scanf function. More details on printf The printf function is usually of the form: printf(string,variable,variable,variable...) where the ... means you can carry on writing an arbitrarily long list of variables separated by commas. The string is all-important because it specifies the type of each variable in the list and how you want it printed. The string is usually called the control string or the format string. The way that this works is that printf scans the string from left to right and prints on the screen, or any suitable output device, any characters it encounters - except when it reaches a % character. The % character is a signal that what follows it is a specification for how the next variable in the list of variables should be printed. printf uses this information to convert and format the value that was passed to the function by the variable and then moves on to process the rest of the control string and anymore variables it might specify. For example: printf("Hello World"); only has a control string and, as this contains no % characters, it results in Hello World being displayed without any variable values. The specifier %d means convert the next value to a signed decimal integer and so: printf("Total =%d",total); will print Total = and then the value of total as a decimal integer. The %d isn't just a format specifier, it is a conversion specifier. It indicates the data type of the variable to be printed and how that data type should be converted to the characters that appear on the screen. That is %d says that the next value to be printed is a signed integer value (i.e. a value that would be stored in a standard int variable) and this should be converted into a sequence of characters (i.e. digits) representing the value in decimal. If by some accident the variable that you are trying to display happens to be a float or a double then you will still see a value displayed - but it will not correspond to the actual value of the float or double. The reason for this is twofold: 1. The first difference is that an int uses two bytes to store its value, while a float uses four and a double uses eight. If you try to display a float or a double using %d then only the first two bytes of the value are actually used. 2. The second problem is that even if there wasn't a size difference ints, floats and doubles use a different binary representation and %d expects the bit pattern to be a simple signed binary integer. This is all a bit technical, but that's in the nature of C. You can ignore these details as long as you remember two important facts: 1. The specifier following % indicates the type of variable to be displayed as well as the format in which that the value should be displayed; 2. If you use a specifier with the wrong type of variable then you will see some strange things on the screen and the error often propagates to other items in the printf list. If this seems complicated then I would agree but I should also point out that the benefit is being able to treat what is stored in a variable in a more flexible way than other languages allow. Other languages never let on to the programmer that what is in fact stored in a variable is a bit pattern. Of course whether you view this as an advantage depends on what you are trying to do. It certainly brings you closer to the way the machine works. More details on scanf scanf is similar to printf in terms of syntax. The only remark is that the name of the variable must be preceded by the symbol &. This has to do with the advanced concept of pointers (later). For now please accept this and remember to include it. An example of input syntax for 3 variables: scanf("%c %d %f",&ch,&i,&x); scanf can be tricky when used to input sequences of characters (strings) as it may not recognise blank characters, such as spaces or newline ("enter"). You will find that this can cause malfunctions in your programs at times. More on this when we will work with strings later. The % Format Specifiers The % specifiers that you can use in ANSI C are: • • • • • • • • • • %c char single character %d (%i) int signed integer %e (%E) float or double exponential format %f float or double signed decimal %g (%G) float or double use %f or %e as required %o int unsigned octal value %p pointer address stored in pointer %s array of char sequence of characters %u int unsigned decimal %x (%X) int unsigned hex value 3.2. Chapter 2: Conditions, Loops and Array 3.2.1 Conditional statements Conditional statements can control the flow of logic in a program. Apart from slight syntactic variation they are similar to other languages. As we have seen following logical operations exist in C: ==, !=, ||, && The NOT operator also exists !. These operators are used in conjunction with the following statements. The if statement The if statement has the same function as other languages. It has three basic forms: If (expression) statement ...or: if (expression) statement1 else statement2 ...or: if (expression) statement1 else if (expression) statement2 else statement3 The switch statement The C switch caters for choice where more than two outcomes are contemplated. It can be much neater than writing multiple if statements: switch (expression) { case item1: statement1; break; case item2: statement2; break; } case itemn: statementn; break; default: statement; break; In each case the value of itemi must be a constant, variables are not allowed. The break is needed if you want to terminate the switch after execution of one choice. Otherwise the next case would be evaluated. Note: This is unlike most other languages. We can also have null statements by just including a semicolon ; or let the switch statement fall through by omitting any statements (see e.g. below). The default case is optional and catches any cases not explicitly stated. For example: switch (letter){ case 'A': case 'E': case 'I': case 'O': case 'U': numberofvowels++; break; case ' ': numberofspaces++; break; default: numberofconstants++; break; } In the above example if the value of letter is `A', `E', `I', `O' or `U' then numberofvowels is incremented. If the value of letter is ` ' then numberofspaces is incremented. If none of these is true then the default condition is executed, that is numberofconstants is incremented. 3.2.2 Looping statements The for statement The C for statement has the following form: for (expression1; 2; expression3) statement; or, alternatively, {block of statements} expression1 initialises; expression2 is the terminate test; expression3 is the modifier (which may be more than just simple increment); For example: int main() { int x; for (x=3;x>0;x--){ printf("x=%d\n",x); } } gives the on-screen outputs x=3 x=2 x=1 Below are other examples of valid statements in C. The practical application of such statements is not important here, we are just trying to illustrate peculiar features of C for that may be useful: for (x=0;((x>3) && (x<9)); x++) for (x=0,y=4;((x>3) && (y<9)); x++,y+=2) for (x=0,y=4,z=4000;z; z/=10) The second example shows that multiple expressions can be separated a comma , . In the third example the loop will continue to iterate until z becomes 0; The while statement The while has the form: while (expression) statement For example: int main() { int x=3; while (x>0) { printf("x=%d\n",x); x--; } } gives the on-screen outputs x=3 x=2 x=1 Because the while loop can accept expressions, not just conditions, the following are all legal: while (x--); while (x=x+1); while (x+=5); Using this type of expression, only when the result of x--, x=x+1, or x+=5, evaluates to 0 will the while condition fail and the loop be exited. The break and continue statements C provides two commands to further control loop operation: • break -- exit from loop or switch. • continue -- skip 1 iteration of loop. Consider the following example where we read in integer values and process them according to the following conditions. If the value we have read is negative, we wish to print an error message and abandon the loop. If the value read is greater than 100, we wish to ignore it and continue to the next value in the data. If the value is zero, we wish to terminate the loop. while (scanf( ``%d'', &value ) == 1 && value != 0) { if (value < 0) { printf(``Illegal value \n''); break; /* Abandon the loop */ } if (value > 100) { printf(``Invalid value \n''); continue; /* Skip to start loop again */ } /* Process in some way the the value read, which is guaranteed to be between 1 and 100 */ ....; ....; } /* end when value no longer != 0 */ 3.2.3 Arrays and Strings In principle arrays in C are similar to those found in other languages. As we shall shortly see arrays are defined slightly differently and there are many subtle differences due the close link between array and pointers (more later). Single and Multi-dimensional Arrays Let us first look at how arrays in C are defined: int listofnumbers[50]; BEWARE: In C, Array subscripts start at 0 and end at index [array length -1]. For example, in the above case valid subscripts range from 0 to 49. This is a BIG difference between C and other languages and does require a bit of practice to get your head around it. Elements can be accessed in the following ways:Thirdnumber = listofnumbers[2]; listofnumbers[5] = 100; Multi-dimensional arrays can also be defined, as follows (two-dimensional example): int ableofnumbers[50][50]; For further dimensions simply add more [ ], e.g., int bigD[50][50][40][30];/*This is 4D*/ Elements can then be accessed in the following ways: anumber = tableofnumbers[2][3]; tableofnumbers[25][16] = 100; Strings In C, strings are defined as arrays of characters. For example, the following defines a string of 50 characters: char name[50]; C has no built-in string handling facilities and therefore the following are all illegal: char firstname[50],lastname[50],fullname[100]; firstname = "Arnold"; /* Illegal */ lastname = "Schwarznegger"; /* Illegal */ fullname = "Mr" + firstname + lastname; /* Illegal */ There is a special library of string handling routines but we will not work with that in this document. To carry out a simple printout of a string we use printf with a special %s control character: printf("%s",name); NOTE: We just need to give the name of the string (no need to specify the array index). In order to allow variable length strings the \0 character is used to indicate the end of a string. So we if we have a string, char name[50]; and we store “DAVE” in it, its contents will look like: Tip for future exercises: you can find the end of a string by locating the \0 character (called null). 3.3. Chapter 3: Functions 3.3.1 Functions In C programming, all executable code resides within a function. A function is a named block of code that performs a task and then returns control to a caller. A function is often executed (called) several times, from several different places, during a single execution of the program. After finishing a subroutine, the program will branch back (return) to the point after the call. Functions are a powerful programming tool. As a basic example, suppose you are writing code to print out the first 5 squares of numbers, do some intermediate processing, then print the first 5 squares again. We could write it like this: #include <stdio.h> int main(void) { int i; for(i=1; i <= 5; i++){ printf("%d ", i*i); } for(i=1; i <= 5; i++){ printf("%d ", i*i); } return 0; } We have to write the same loop twice. We may want to somehow put this code in a separate place and simply jump to this code when we want to use it. This would look like: #include <stdio.h> void Print_Squares(void) { int i; for (i=1; i <=5; i++){ printf("%d ", i*i); } } int main(void) { Print_Squares(); Print_Squares(); return 0; } This is precisely what functions are for. More on functions A function is like a black box. It takes in input, does something with it, then spits out an answer. Note that a function may not take any inputs at all, or it may not return anything at all. In the above example, if we were to make a function of that loop, we may not need any inputs, and we aren't returning anything at all (Text output doesn't count - when we speak of returning we mean to say meaningful data that the program can use). We have some terminology to refer to functions: • A function, call it f, that uses another function g, is said to call g. For example, f calls g to print the squares of ten numbers. • A function's inputs are known as its arguments • A function g that gives some kind of answer back to f is said to return that answer. For example, g returns the sum of its arguments. Writing functions in C It's always good to learn by example. Let's write a function that will return the square of a number. int square(int x) { int square_of_x; square_of_x = x * x; } return square_of_x; To understand how to write such a function like this, it may help to look at what this function does as a whole. It takes in an int, x, and squares it, storing it in the variable square_of_x. Now this value is returned. The first int at the beginning of the function declaration is the type of data that the function returns. In this case when we square an integer we get an integer, and we are returning this integer, and so we write int as the return type. Next is the name of the function. It is good practice to use meaningful and descriptive names for functions you may write. It may help to name the function after what it is written to do. In this case we name the function "square", because that's what it does - it squares a number. Next is the function's first and only argument, an int, which will be referred to in the function as x. This is the function's input. In between the braces is the actual guts of the function. It declares an integer variable called square_of_x that will be used to hold the value of the square of x. Note that the variable square_of_x can only be used within this function, and not outside. We'll learn more about this sort of thing later, and we will see that this property is very useful. We then assign x multiplied by x, or x squared, to the variable square_of_x, which is what this function is all about. Following this is a return statement. We want to return the value of the square of x, so we must say that this function returns the contents of the variable square_of_x. Finally, the brace is closed, and we have finished the declaration. Written in a more concise manner, this code performs exactly the same function as the above: int square(int x) { return x * x; } Technically, you have been writing functions already, in fact - main is a function that is always written. Note: main is always of type int in this document. Discussion of this might take us astray. Please accept it is standard C practice. General function declaration In general, if we want to declare a function, we write type name (type1 arg1, type2 arg2, ...) { /* code */ } We’ve previously said that it is possible for a function to take no arguments, or return nothing, or both. When a function does not return anything the type void is used. void basically means "nothing" so if we want to write a function that returns nothing, for example, we write void sayhello(int number_of_times) { int i; for (i=1; i <= number_of_times; i++){ printf("Hello!\n"); } } Notice that there is no return statement in the function above. Since there's none, we write void as the return type. Below is an example of a function with no arguments: float calculate_number(void) { float to_return=1; int i; for (i=0; i < 100; i++){ to_return += 1; to_return = 1/to_return; } return to_return; } Notice this function doesn't take any inputs, but merely returns a number calculated by this function. Naturally, it is possible to also have a function with both void return and void in arguments together. Using C functions We can now write functions, but how do we use them? When we write main, we place the function outside the braces that encompass main. When we want to use that function, say, using our calculate_number function above, we can write something like float f; f = calculate_number(); In general a function call is done as follows. If a function takes in arguments, we can write something like int square_of_10; square_of_10 = square(10); If a function doesn't return anything, no “assignment to a variable” is required and we can just write say_hello(); since we don't need a variable to catch its return value. Recursion An advanced way of using functions. Not for the faint hearted and risky as it can exhaust memory resources very quickly. On the other hand, it can create very neat and efficient code. Recursion occurs when a function calls itself as part of its operation. An example: Write a C program to find sum of first n natural numbers using recursion. #include <stdio.h> int sum(int n); int main() { int num, add; printf("Enter a positive integer:\n"); scanf("%d",&num); add=sum(num); printf("sum=%d",add); } int sum(int n){ if(n==0) return n; else return n+sum(n-1); } /*self call to function sum() */ The output will look as follows: Enter a positive integer: 5 15 In this simple C program, the sum() function invokes itself. If n is not equal to 0 then, the function calls itself passing argument 1 less than the previous argument it was called with. Suppose, n is 5 initially. Then, during next function calls, 4 is passed to function and the value of argument decreases by 1 in each recursive call. When, n becomes equal to 0, the value of n is returned which is the sum numbers from 5 to 1. A way to visualise the recursion is shown below: sum(5) =5+sum(4) =5+4+sum(3) =5+4+3+sum(2) =5+4+3+2+sum(1) =5+4+3+2+1+sum(0) =5+4+3+2+1+0 =5+4+3+2+1 =5+4+3+3 =5+4+6 =5+10 =15 Every recursive function must be provided with a way to end the recursion. In this example when, n is equal to 0, there is no recursive call and recursion ends. Standard C functions and libraries A number of standard libraries exist which contain many pre-prepared functions. We have seen the stdio.h file in the Hello World example earlier. printf and scanf are functions declared and described inside the stdio.h file. A file can contain multiple functions. There are many more header files in the standard libraries, a list of the most common is below*. <assert.h> <ctype.h> <errno.h> <float.h> <limits.h> <locale.h> <math.h> <setjmp.h> <signal.h> <stdarg.h> <stddef.h> <stdio.h> <stdlib.h> <string.h> <time.h> <complex.h> 3.4. Chapter 4: Pointers 3.4.1 Pointers Pointers are a very powerful, but primitive facility contained in the C language. Pointers have great affinity with low-level assembly language programming and as a result they are sometimes difficult to understand and subject to subtle and difficult-to-find errors. Still, pointers are one of the great attractions of the C language and most C programmers would object to the idea that pointers are 'primitive'! Since we will use C on microprocessors, pointers are an important topic for our purposes. A variable is an area of memory that has been given a name. For example, int x; is an area of memory that has been given the name x. The advantage of this scheme is that you can use the name to specify where to store data. For example, x=10;is an instruction to store the data value 10 in the area of memory named x. The variable is such a fundamental idea that using it quickly becomes second nature, but there is another way of working with memory. The computer accesses its own memory not by using variable names but by using a memory map with each location of memory uniquely defined by a number, called the address of that memory location. A pointer is a variable that stores a memory location. In more fundamental terms, a pointer stores the memory address of a variable. A pointer “points” to a variable. A pointer has to be declared just like any other variable - remember a pointer is just a variable that stores an address. For example, int *p; is a pointer to an integer. Adding an asterisk in front of a variable's name declares it to be a pointer to the declared type. Notice that the asterisk applies only to the single variable name that it is in front of, so int *p, q;, for example, declares one pointer to an int and one int variable, not two pointers. Pointer operators Once you have declared a pointer variable, you can begin using it like any other variable. First, however, there are new operators you must understand: & and *. The & operator returns the address of a variable. Thinking of the ampersand (&) symbol as the ‘A’ for ‘address’ might help you remember. For example: int *p, q; declares p, a pointer to int, and q an int. The instruction p=&q; stores the address of q in p. After this instruction you can think that p is pointing at q. Compare this with p=q;, which attempts to store the value in q in the pointer p - something which has to be considered an error since a pointer contains the address, not the value of a variable. The * operator returns the value of the variable pointed at by the address saved in the pointer. This operation is a little more difficult to understand. In other words, p stores the address, or pointer, to another variable and *p is the value stored in the variable that p points at. The * operator is called the de-referencing operator and you should not confuse it with multiplication. [The multiple use of the asterisk symbol (i.e., for pointers and multiplication depending on the context) is an example of operator overload in C]. Much confusion over pointers can be avoided by focussing on three basic ideas: • To declare a pointer, add * in front of its name. • To obtain the address of a variable, use & in front of its name. • To obtain the value of a variable, use * in front of a pointer's name. Here is a worked example: int *a , b , c; b = 10; a = &b; c = *a; Firstly, three variables are declared: a (a pointer to int), and b and c (both standard integers). The instruction stores the value 10 in the variable b in the usual way. Then a=&b; stores the address of b in a. After this, a points to b. Finally, c=*a; stores the value in the variable pointed to by a into c. As a points to b, its value i.e. 10 is stored in c. In other words, this is a long winded way of writing c=b; Notice that if a is an int and p is a pointer to an int then a=p; is nonsense because it tries to store the address of an int, i.e. a pointer value, in an int. Similarly: a=&p; tries to store the address of a pointer variable in a and is equally wrong! The only assignment between an int and a pointer to int that makes sense is: a=*p; Pointers and functions At the moment it looks as if pointers are just a complicated way of doing something we can already do by simpler methods. Pointers are, however, extremely powerful tools. A useful area of application is their involvement in function calls. We did not specifically look at this when we discussed functions but functions can have arguments passed to them either by value or by address. Let’s have a look at the following code, which tries to implements a simple variable swap: void swap(int x , int y) { int temp; temp = x; x = y; y = temp; } int main() { int a, b; a=10; b=5; swap(a,b); printf(“Values: a is %d and b is %d”,a,b); } This code suffers from a major problem: although a swap function is created and executed as part of the main, the result of the printf statement will be: “Values: a is 10 and b is 5.”. It appears that the variables have not been swapped after all. Why?? The function arguments in this example are passed by value. This means that the invoked function creates copies (located in other available memory locations) of the variables passed (the ‘copies’ are called x and y in this example). These new variables are local to the function (i.e., they are not seen by the main) and any changes made do not affect the original a and b. Furthermore, the function created is of return type void, which suggests that it does not return anything to the calling function main. Of course one could rectify this by creating a non-void function (although using structures to pass multiple outputs might be undesirably complex), or by using global variables†. Pointers offer a much neater way to achieve the desired result. Look at the code below: void swap(int *x , int *y) { int temp; temp = *x; *x = *y; *y = temp; } int main() { int a, b; a=10; b=5; swap(&a,&b); printf(“Values: a is %d and b is %d”,a,b); } This code passes the arguments by address. Note the use of & in the invoking statement. This means that the invoked function receives the memory addresses of the variables. The use of pointers inside the function ensures that any changes made are performed onto those very memory addresses used by main. Therefore, in this case the values of a and b will be correctly swapped and the output will be: “Values: a is 5 and b is 10.”. You can try to write and run this code yourself to get some handson feel for how it works. The rule is that whenever you want to pass a variable so that the function can modify its contents you have to pass it as an address. Equally, the function has to be ready to accept an address and work with it. You can't take any old function and suddenly decide to pass it the address We haven’t discussed these, but global variables can be seen and modified by all functions in a program, as opposed to local variables (the ‘standard’ type) which are only seen by the function they are declared in. † of a variable instead of its value. If you pass an address to a function that isn't expecting it, the result is usually disaster and the same is true if you pass a value to a function that is expecting an address. For example, in the second version of the code, calling swap as swap(a,b) instead of swap(&a,&b) will result in two arbitrary areas of your computer’s memory being swapped over, usually with the result that the entire system, not just your program, crashes. The need to pass an address to a function also explains the difference between the two I/O functions that we have been using since the beginning of this course. printf doesn't change the values of its parameters so it is called as printf("%d",a), but scanf does, being an input function, and so it is called as scanf("%d",&a). Pointers and arrays (basic pointer arithmetic) Another area where pointers become extremely useful is when handling arrays. In C there is a very close connection between pointers and arrays. In fact they are more or less one and the same thing! When you declare an array as: int a[10]; you are in fact declaring a pointer a to the first element in the array. That is, a (with no index attached) has the same meaning in the program as &a[0]. The only difference between the bare array name (a in this case) and a pointer variable is that the array name is a constant pointer - you cannot change the location it points at. Another pointer in disguise is the expression a[i]: this is converted by the compiler into a pointer expression that gives the value of the appropriate element. To be more precise, writing a[i] is exactly equivalent to *(a+i) i.e. the a[1] returns the value located at address a+i. In the same way *(a+1) is equivalent to a[1] and so on. The strange concept here is the idea of adding ‘one’ to the address stored in a pointer to get to the next element of an array. What it means to add 'one' to a pointer? In most implementations, an int takes two memory locations and a float takes four. So if you declare an int array and add one to a pointer to it, then in fact the pointer will move on by two memory locations. However, if you declare a float array and add one to a pointer to it then the pointer has to move on by four memory locations. In other words, adding one to a pointer moves it on by an amount of storage depending on the type it is a pointer to. This is precisely why you have to declare the type that the pointer is to point at! Only by specifying, e.g., int a[10]; (a pointer to int array) and float b[10]; (b pointer to float array) can the compiler figure out that a+1 means move the pointer on by two memory locations and b + 1 means move the pointer on by four memory locations. In practice, you don't have to worry about how much storage a pointer's base type takes up. All you do need to remember is that pointer arithmetic works in units of the data type that the pointer points at. Notice that you can even use increment and decrement operators ++ and -- with a pointer, but not with an array name because this is a constant pointer and cannot be changed. Summarising the key ideas: 1. An array's name is a constant pointer to the first element in the array that is a ≡ &a[0] and *a ≡ a[0]. 1 2. Array indexing is equivalent to pointer arithmetic - that is a+i ≡ &a[i] and *(a+i) ≡ a[i]. Pointers, arrays and functions One final point connected with both arrays and functions is that when you pass an entire array to a function then by default you pass a pointer. This allows you to write functions that process entire arrays without having to pass every single value stored in the array - just a pointer to the first element. If you compare this with a hypothetical alternative option of passing an array by value, i.e., copying all of the array elements in a local copy for use by a function, you should be able to see how passing pointers between functions is a much less resource-intensive option. However, unless the concepts are clear in your head, you could easily write code which causes your computer to crash altogether. Here is an example of a program featuring a function which assigns numbers 1 to n to an array of int of size n. void enum_fcn(int *pa, int n) //pa a handy name for “pointer to array” { int i; for (i=0;i<n;i++){ *pa = i+1; //assigning a value to the location pointed at pa++; //incrementing the pointer } } 1 the symbol ≡ means ‘is identical to’ } int main() { int a[5], i; int arr_size=5; enum_fcn(a,arr_size); for (i=0;i<arr_size;i++) printf (“%d\t”,a[i]); } The output will be: 1 2 3 4 5 Note how the array was passed to the function as a and not &a, that is because a is a bare array name and automatically represents the address of a[0] as previously explained. Also, if your understanding of these pointer concepts is good, you should also be able to see that I could have used this equivalent header for my function: void enum_fcn(int pa[], int n). Common pointer mistakes Not assigning a memory address to a pointer before using it, as in int *x; *x = 100; This may be hard to spot because it will not raise a compiler error. x may be initialised randomly so the value 100 will be written in a random location of your memory (potentially overwriting useful memory information and causing havoc in your computer). Always ensure a location is assigned, e.g., x = &y; *x = 100; Illegal indirection. Assigning a value to a pointer or an address to a variable, as in int y, *p; or int *a, b; p = y *a = &b; This may also fail to irritate the compiler and cause undesired program behaviour. 3.5. Chapter 5: Structures In Chapter 5 you should do a good review of all of the previous Chapters. There is not too much new content, but the exercises will test your skills in all of the previous areas as well. 3.5.1 Structures An array is an example of a data structure. It takes simple data types like int, char or double and organises them into a linear array of elements. The array serves most but not all of the needs of the typical C program. The restriction is that an array is composed of elements all of the same type. At first this seems perfectly reasonable. After all why would you want an array to be composed of twenty chars and two ints? Well this sort of mixture of data types working together is one of the most familiar of data structures. Consider for a moment a record card which records name, age and salary. The name would have to be stored as a string, i.e. an array of chars terminated with an ASCII null character, and the age and salary could be ints. At the moment the only way we could work with such a collection of data is as separate variables. This isn't as convenient as a single data structure using a single name and so the C language provides struct as a way to define such collections of different variable types and sizes. At first it is easier to think of this as a record - although it's a little more versatile than this suggests. Defining new structures Declaring a struct is a two-stage process. The first stage defines a new data type that has the required structure which can then be used to declare as many variables with the same structure as required. This two-stage process is best explained by example. For example, suppose we need to store a name, age and salary as a single structure. You would first define the new data structure; this is done outside the main type using: struct emp_record{ char name[25]; int age; int pay; }; And then, in the main code, the variable is declared: struct emp_record employee Notice that the new variable is called employee and it is of type emp_record which has been defined earlier. emp_record is the name of the general employee record structure and employee is one instance of this general type. It might help to compare the situation with that of a general int type and a particular variable such as int count - emprec is a type like int (albeit user defined) and employee is a variable like count. The following code, for example, creates three employee records: struct emp_record employee, oldemploy, newemploy;. The next problem when working with a structure is how to access the individual elements. The syntax is structure_variable.component. For example, I could assign: employee.age = 32; employee.name[2] = 'a'; and so on. It should be clear by now that a structure has a different value to that of an array. A struct can be used to cluster together a group of variables which form a coherent entity. A useful example follows. C does not have facilities to handle complex numbers, but it is possible to create an ad-hoc structure which comprises of two numbers representing the real and imaginary parts. struct comp{ float real; float imag; }; After this you can declare the new complex variables using something like: struct comp a,b; The new complex variables cannot be used as if they were simple variables - because they are not. Although it might depend on your compiler version, the C language does not in general allow you to do whole-of-structure operations such as: a=b; However, the extended version will definitely work: a.real=b.real; a.imag=b.imag; Similarly, the compiler will not be able to sort out what you mean by c = a + b, so you will have to write out the rule for addition (e.g., in a function) as: c.real=a.real+b.real; c.imag=a.imag+b.imag; Structures and functions Of course a sensible alternative to writing out the addition each time is to define a function to do the same job - but this raises the question of passing structures as parameters. Fortunately this isn't a big problem. It is possible to pass entire structures as parameters and set a structure as return type for a function. Here is an example for the complex number addition: struct comp add(struct comp a , struct comp b){ struct comp c; c.real=a.real+b.real; c.imag=a.imag+ b.imag; return c; } After the add function has been written you can call upon it to perform a complex addition as x=add(y,z) which isn't too far from the x=y+z that you would really like to use. Finally notice that passing a struct by value might use up rather a lot of memory as a complete copy of the structure is made for the function, especially if the structure is large. It is of course possible to pass a pointer instead of a value. Structures and pointers You can define a pointer to a structure in the same way as any pointer to any type. For example: struct emp_record *ptr // ptr = "pointer to record" ptr = &employee; defines a pointer to an emp_record and associates to the memory address of employee. You can use a pointer to a struct in more or less the same way as any pointer. There are just some peculiarities about addressing the components internal to the structure. For this there are two equivalent syntax options. For example: (*ptr).age ptr->age //equivalent ways to point to the 'age' component The latter is most often used because it does not require the use of brackets and also the arrow symbol is quite intuitive. Below is the complex addition function rewritten with pointers: void comp add(struct comp *a , struct comp *b , struct comp *c) { c->real = a->real + b->real; c>imag = a->imag + b->imag; } In this case c is a pointer to a structure of type comp. The function in the main program would be called as: add(&x,&y,&z); Notice that in this case the address of each of the structures is passed rather than a complete copy of the structure - hence the saving in memory! Also notice that the function can now change the values of x, y and z if it wants to. It's up to you to decide if this is a good thing or not! Arrays of structures It is also possible to have arrays of structures. For example, I can cater for all of my company's employees by creating: struct emp_record employees[100]; which is an array of 100 identical employee records. The statement printf("%d",employees[6].age); will print to screen the age of the employee saved in record 6. 4. EXERCISES These are recommended exercises. They are not mandatory and you could work on other exercises if you like. There is a wealth of information out there. The main point of this section is to help you get a minimum of programming experience under your belt. 4.1. Chapter 1: Write C programs to perform the following tasks. Exercise 1.1 Input two numbers and work out the difference, average and sum of the squares of the numbers. Exercise 1.2 Write a program to read a "float" representing a number of degrees Celsius, and print (also as a "float") the equivalent temperature in degrees Fahrenheit. Print your results in a form such as 100.0 degrees Celsius converts to 212.0 degrees Fahrenheit. Exercise 1.3 Write a program which will ask you about your name, student number and favourite colour and print those on separate lines. You may use either several printf instructions, each with a newline character in it, or one printf with several newlines in the control string. Note: Your name is an array of characters. We will look at arrays later on but I will give you an example of a declaration of a char array of 10 letters just for the purpose of this exercise char a[10]§. Don't forget to use the correct type specifier for a string of characters in your i/o functions. Exercise 1.4 Write a program to read a number of units of length (a float) and print out the area of a circle of that radius. Assume that the value of pi is 3.14159. Your output should take the form: The area of a circle of radius ... units is .... units. If you want to be clever, and have looked ahead in the notes, print the message "Error: Negative values not permitted." if the input value is negative. Exercise 1.5 Given as input an integer number of seconds, print as output the equivalent time in hours, minutes and seconds. Recommended output format is something like 7322 seconds is equivalent to 2 hours 2 minutes 2 seconds § I did mention that scanf can do silly things when dealing with inputting spaces or characters/strings terminated with "enter". This should not concern us too much at this time. If you are encountering problems, for now, consider the below scanf formulations as hints for you go through your exercises (it's ok if you do not fully understand them). scanf(" %c", &c); \\ to input a single character e.g. char c. Note the space before %c scanf("%[^\n]s", &c[0]); \\ if you enter a string e.g. char c[10] terminated by "enter" Exercise 1.6 Write a program to read two integers with the following significance. The first integer value represents a time of day on a 24 hour clock, so that 1245 represents quarter to one mid-day, for example. The second integer represents a time duration in a similar way, so that 345 represents three hours and 45 minutes. This duration is to be added to the first time, and the result printed out in the same notation, in this case 1630 which is the time 3 hours and 45 minutes after 12.45. Typical output might be e.g., Start time is 1415. Duration is 50. End time is 1505. Start time is 2300. Duration is 200. End time is 100. You are not allowed to use if... else statements to solve this exercise. You can however, use expressions containing comparison operator, e.g., the expression x_gr_zero=(x>0)*x; yields x for x>0 and 0 otherwise. 4.2. Chapter 2: Exercise 2.1 Write a program to read two characters, and print their decimal value when interpreted as a 2-digit hexadecimal number. Accept upper case letters for values from 10 to 15. Return an error for invalid entries. Exercise 2.2 Read an integer value. Assume it is the number of a month of the year; print out the name of that month. If the number is invalid, print an error message. Write a program that repeats this for 3 month entries. Exercise 2.3 Write a program to read in 10 numbers and compute the average, maximum and minimum values. Finally, sort them in order to get an output something like (only 5 numbers shown): (hint for printing to screen: just as \n means a new line, \t introduces a tabulation) You entered 10 15 2 1 43 The sorted list is 1 2 10 15 43 Exercise 2.4 Write a program to read in numbers until the number -999 is encountered. The sum of all number read until this point should be printed out. TIP: you don’t need to use arrays for this exercise. Exercise 2.5 Read in three values representing respectively: 1) a capital sum (integer number of dollars), 2) a rate of interest in percent (float), and 3) a number of years (integer). Compute the values of the capital sum with compound interest added over the given period of years. Each year's interest is calculated as interest = capital * interest_rate / 100; and is added to the capital sum by capital += interest; Print out money values in dollars accurate to two decimal places. (hint: try and use output format %.nf to get n decimal places) Print out a floating value for the value with compound interest for each year up to the end of the period. Print output year by year in a form such as: Original sum 30000.00 at 12.5 percent for 10 years Year Interest Sum ----+-------+-------1 3750.00 33750.00 2 4218.75 37968.75 3 4746.09 42714.84 4 5339.35 48054.19 5 6006.77 54060.96 6 6757.62 60818.58 7 7602.32 68420.90 8 8552.61 76973.51 9 9621.68 86595.19 10 10824.39 97419.58 Exercise 2.6 Read a positive integer value, and compute the following sequence: If the number is even, halve it; if it's odd, multiply by 3 and add 1. Repeat this process until the value is 1, printing out each value. Finally print out how many of these operations you performed. Typical output might be: Initial value is 10 Next value is 5 Next value is 16 Next value is 8 Next value is 4 Next value is 2 Final value 1, number of steps 5 If the input value is less than 1, print a message containing the word Error Exercise 2.7 Write a function that asks for an input n and outputs a right-side-up triangle of height n and width 2n1; the output for n = 6 would be: * *** ***** ******* ********* *********** Exercise 2.8 Write a program which asks you to input your student number (XXXXXXX) and then presents you with a menu for the following operations (by inputting a number the corresponding activity is executed): 1. Write the number back to you in reverse order 2. Asks you to state a digit number n, then prints the nth character of the student number 3. Asks you for a particular character and tells you if it is found in the student number 4. Quit After each operation (except ‘quit’), the program goes back to the main menu. 4.3. Chapter 3: Exercise 3.1 Write a function to check if an integer is negative; the declaration should look like int is_positive(int i); The program will keep asking for inputs and will keep delivering outputs (informing the user of whether the number is negative or not) until the number entered is 999 (such input will force quit). Exercise 3.2 Write a function with two arguments to raise a floating point number to an integer power, so for example: float a = raise_to_power(2, 3); //a gets 8 float b = raise_to_power(9, 2); //b gets 81 float raise_to_power(float f, int power); //make this your declaration The program will keep asking for inputs and will keep delivering outputs (informing the user of the computed result) until the numbers entered are 999, 999 (such input will force quit). Note: you are not allowed to use the function pow here (elevating to power) but should rather use iterative multiplication to compute the result. Exercise 3.3 Write a function which returns 1 if a positive integer is prime and 0 otherwise. A prime number can only be divided (without remainder) by itself and by 1. (hint, the modulo operator % might be helpful for your function) Exercise 3.4 Write a function to determine the number and identity of all prime numbers below an inputted positive number n. To check operation, try at least two separate runs for values of n in excess of 41. Hint: have you solved the exercise above? Exercise 3.5 Write a program to calculate the factorial of an integer number using recursion (hint: very similar to the example in the concepts section). Remember that 3!=3*2*1=6 and 0!=1. Create suitably explanatory inputs and outputs. Exercise 3.6 Write a function called half() that takes an integer argument. The function must print the number it received to the screen, then the program should divide that number by two to make a new number. If the new number is greater than zero the function then calls the function half() (itself!) passing it the new number as its argument. If the number is zero or less than zero the function exits. So, for example, calling the function half() with an argument of 100, the screen output should be 100 50 25 ... ... 1 4.4. Chapter 4: Exercise 4.1 Write a C program that asks the user for an input and stores it in a variable. Then, the program prints out something like. The value entered is <value> and is stored at memory location <location value>. Tip: use the %p type identifier to visualise the memory address (pointer value) in hexadecimal format. Exercise 4.2 Write a program that takes three variable (a, b, c) in as separate parameters and calls on a function which rotates the values stored so that value a goes to b, b to c and c to a. Output the values of your variables before and after the swap in an understandable manner. Exercise 4.3 Write a program that creates an array of type float. How you populate this array is up to you. Print out the content of the array and the corresponding memory addresses for each entry. (you may want to try with both equivalent ways of referencing an array to make sure your syntax is up to speed). Take note of the numeric difference between successive address entries. What does that suggest regarding the way the array is stored to memory? What is the size of a float entry? Exercise 4.4 Write a C program to read through an array of type int using pointers. How you populate this array is up to you. Write the array to screen so that it fits in one screenshot. Then ask the user to input a value. Your C program is to scan through the array to find the value and output how many occurrences were found. You must use pointers. Exercise 4.5 Write a program to find the number of times that a given word (i.e. a short string) occurs in a sentence (i.e. a long string!). Read data from standard scanf input (you will store two arrays of char to memory). You will first acquire a single word, and then a longer string of general text. Your program should pass the two strings to a function which will count the number of occurrences. Extension: Let the function also turn any blank spaces into dashes. Typical output should be something like: The word is "the". The sentence is "the cat sat on the mat". The word occurs 2 times. If I remove the spaces: "the-cat-sat-on-the-mat" Important Tip: when you type a space scanf will think that your string is finished. The syntax: scanf("%[^\n]s", c);, where c will be your string array, will ignore the spaces and capture the string as a whole once the enter key is pressed (it sets \n as the string delimiter). By the way, note that the variable is passed as c and not &c, you should be able to tell why. 4.5. Chapter 5: Exercise 5.1 Implement, using structures and functions as appropriate, the sum and product of two fractions. Simplification is not required. To get full marks, you should pass your structures to your functions as pointers. Exercise 5.2 Implement, using structures and functions as appropriate, a program which requires you to enter a number of points in 3 dimensions. The points will have a name (one alphanumeric character) and three coordinates x, y, and z. Find and implement a suitable way to stop the input loop. The program, through an appropriate distance function, should identify the two points which are the furthest apart. Another function should calculate the centre of gravity of the point cloud (i.e., the average of each coordinate for all points entered) The output should show a list of the points entered, then name and list the two that are furthest apart, and finally list the centre of gravity. Exercise 5.3 Create a C program which describes a store management software. The records will be saved in a structure called goods. You can have up to 10 goods in your store (array of struct). Each good will have a name, a record id (sequential numbering), a price, and a flag as to whether it is in stock or not. Use appropriate variable types for each. Your program will present a menu, allowing the user to choose: 1. Open record (by number) 2. List all records 3. Quit Quit is self-explanatory. List all records will print out a list of record IDs and product names. If Open record is selected, then the program should show Record <number> opened <a list of the details of the item should appear here> And give the following options: 1. Change item name 2. Change item price 3. Change stock availability 4. Go back After a suboption has been chosen, the user should have the opportunity to enter the new name/price or toggle availability. Then the program should show the updated details of the record and show the second menu for a new choice. Create a suitable main program structure which calls on functions which will carry out the operations as described, asking for appropriate inputs and returning appropriate outputs. Note: you should use pointers when passing structs to functions.