Вы находитесь на странице: 1из 172

SIEMENS Technical Academy Licensed vocational school for Industry technologists, electro-technical assistants and technical assistants of informatics

Ruth Schubert

C - Course
Teacher's book

20.03.99

Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

1 Content
1 Content.........................................................................................................................................2 2 General considerations regarding C-training.................................................................................7 3 C development.............................................................................................................................8 4 Introduction...................................................................................................................................9 4.1 Basic principle of data processing .........................................................................................9 4.2 What is a program ?...............................................................................................................9 4.3 Program generation with higher programming languages.....................................................10 4.4 The shortest possible C-program..........................................................................................10 4.5 Simple program with in- and output......................................................................................10 4.6 Programs input.....................................................................................................................11 4.6.1 The Editor in the integrated environment of BORLAND-C 3.1........................................11 4.6.1.1 General...................................................................................................................11 4.6.1.2 Block commands.....................................................................................................11 4.6.1.3 Editing commands...................................................................................................12 4.6.1.4 Additional commands .............................................................................................12 4.6.2 About vi.........................................................................................................................12 4.6.2.1 Calling vi.................................................................................................................12 4.6.2.2 The command mode ...............................................................................................12 4.6.2.2.1 Moving in the text..............................................................................................13 4.6.2.2.2 Changing to input mode ...................................................................................13 4.6.2.2.3 Searching in the text.........................................................................................13 4.6.2.2.4 Deletion of text..................................................................................................14 4.6.2.2.5 Copying of text..................................................................................................14 4.6.2.2.6 File insertion.....................................................................................................14 4.6.2.2.7 quit vi................................................................................................................14 4.6.2.3 The input mode.......................................................................................................14 4.7 Pre-processor.......................................................................................................................15 4.7.1 Control of pre-processor function with cc.......................................................................15 4.7.2 Control of pre-processor function with cpp.....................................................................16 4.7.3 Overview of pre-processor instructions..........................................................................16 4.7.4 Symbolic constants .......................................................................................................16 4.7.5 Macros...........................................................................................................................17 4.7.5.1 The pre-processor operator "#"................................................................................18 4.7.5.2 The pre-processor operator "##"..............................................................................18 4.7.5.3 Deleting the definition of a previous #define............................................................19 4.7.6 Insertion of files .............................................................................................................19 4.7.6.1 Standard path for includes in UNIX systems............................................................20 4.7.6.2 Standard path for includes at BORLAND C.............................................................20 4.7.7 Conditioned translation .................................................................................................20 4.7.7.1 Symbol generation for UNIX....................................................................................22 4.7.7.2 Symbol generation for BORLAND-C........................................................................22 4.8 Calling the C-compiler and the binder...................................................................................23 4.8.1 cc (Compiler call)...........................................................................................................23 4.8.2 ld (Binder call)................................................................................................................24 4.8.3 ld call through the C-Compiler........................................................................................25

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5 C speech elements.....................................................................................................................26 5.1 Identifier...............................................................................................................................26 5.1.1 Reserved names / C-keywords / Keywords....................................................................27 5.2 Data types............................................................................................................................27 5.3 Variables..............................................................................................................................29 5.4 Constants.............................................................................................................................31 5.4.1 Constant routine............................................................................................................32 5.4.2 Boolean constants.........................................................................................................32 5.5 In / Output............................................................................................................................33 5.5.1 Character by character in/output....................................................................................34 5.5.1.1 putchar() output.......................................................................................................34 5.5.1.2 Input with getchar()..................................................................................................35 5.5.2 Formatted in/output........................................................................................................36 5.5.2.1 Output with printf.....................................................................................................36 5.5.2.1.1 Sintactic structure of the printf function call ......................................................36 5.5.2.1.2 Structure of a formatting specification for printf..................................................37 5.5.2.2 Input with scanf.......................................................................................................40 5.5.2.2.1 Syntactic structure of the scanf function call .....................................................41 5.5.2.2.2 Structure of a formatting specification for scanf.................................................41 5.6 Operators and routines.........................................................................................................44 5.6.1 Overview of operators in C.............................................................................................44 5.6.2 C - Specialties................................................................................................................44 5.6.3 Simple assignment operator ..........................................................................................44 5.6.4 Arithmetic operators.......................................................................................................45 5.6.5 Comparison operators...................................................................................................45 5.6.6 Logical operators...........................................................................................................46 5.6.7 Operators for Bit-manipulation.......................................................................................47 5.6.8 Compound assignment operators .................................................................................48 5.6.9 Increment and decrement operators..............................................................................49 5.6.9.1 Prefix quote.............................................................................................................49 5.6.9.2 Postfix quote...........................................................................................................50 5.6.10 sizeof...........................................................................................................................50 5.6.11 Conditioned routines....................................................................................................51 5.6.12 Priority and assessment of operators...........................................................................51 5.6.13 Routines......................................................................................................................52 5.6.14 Side effects in routines ................................................................................................52 5.6.14.1 Rules for avoiding side effects ..............................................................................54 5.7 Control structures.................................................................................................................55 5.7.1 Blocks............................................................................................................................55 5.7.2 if-branching....................................................................................................................55 5.7.2.1 General form of the if-branching..............................................................................55 5.7.2.2 if-instruction without else-branch.............................................................................56 5.7.2.3 Nested if-instructions...............................................................................................56 5.7.2.4 else-if-chains...........................................................................................................57 5.7.2.5 Some common errors when handling if-queries.......................................................58 5.7.3 switch-instruction...........................................................................................................59 5.7.3.1 Basic form of switch-instruction...............................................................................59 5.7.3.2 Variant with partly missing break-instructions..........................................................61 5.7.4 while loop....................................................................................................................63 5.7.4.1 Standard form of a while-loop..................................................................................64 5.7.4.2 while-loop with empty loop body .............................................................................65

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.7.5 do - while loop.............................................................................................................65 5.7.6 for loop.......................................................................................................................66 5.7.7 break- instruction...........................................................................................................68 5.7.8 continue - Instruction......................................................................................................68 5.7.9 goto - Instruction / Brands..............................................................................................69 5.8 Data type conversions..........................................................................................................70 5.8.1 The implicit conversion of the data type ........................................................................70 5.8.2 The explicit conversion of the data type ........................................................................71 5.9 Fields (Arrays)......................................................................................................................72 5.9.1 Unidimensional errors ...................................................................................................72 5.9.2 Multidimensional fields ..................................................................................................73 5.9.3 Initialization of fields at definition ...................................................................................74 5.10 Pointer................................................................................................................................75 5.10.1 Definition of a pointer ..................................................................................................76 5.10.2 The address of a variable ............................................................................................76 5.10.3 The content of a memory cell addressed over a pointer ..............................................76 5.10.4 Example of a memory allocation with variables and pointers .......................................77 5.10.5 Pointer arithmetics.......................................................................................................78 5.10.6 Pointers and fields ......................................................................................................80 5.10.6.1 Connection between physical address and pointer arithmetics .............................80 5.10.7 char - pointer (Strings).................................................................................................81 5.10.7.1 Strings as function parameters..............................................................................81 5.10.7.2 Strings in assignments to char-pointers.................................................................82 5.10.7.3 Strings when initializing char-fields........................................................................83 5.10.7.4 Standard functions for string handling ...................................................................83 5.10.8 Pointer errors...............................................................................................................84 5.10.8.1 Definition of a pointer field.....................................................................................84 5.10.8.2 Assignment of an address to a field element..........................................................84 5.10.8.3 Access to an addressed object..............................................................................85 5.10.9 Pointer on pointer ........................................................................................................85 5.10.9.1 Definition...............................................................................................................85 5.10.9.2 Allocation..............................................................................................................85 5.10.9.3 Access..................................................................................................................85 5.11 Functions...........................................................................................................................86 5.11.1 Function definition........................................................................................................86 5.11.2 Function call ................................................................................................................87 5.11.3 Function declaration.....................................................................................................89 5.11.4 Result transfer through the return value ......................................................................90 5.11.5 Parameter transfer.......................................................................................................90 5.11.5.1 Type test of parameters under UNIX.....................................................................91 5.11.5.2 Function parameters as value ("call by value").......................................................91 5.11.5.3 Function parameters as address ("call by reference")............................................91 5.11.6 Argument transfer to the main-function........................................................................92 5.11.7 Pointer on functions ....................................................................................................94 5.11.7.1 Definition of a function pointer ..............................................................................94 5.11.7.2 Assigning a function's address ..............................................................................95 5.11.7.3 Calling the function through the function pointer....................................................95 5.11.7.4 Sorting of fields with "qsort"...................................................................................96 5.11.8 Recursive function call ................................................................................................98 5.11.9 Complex definitions....................................................................................................100 5.12 Memory classes...............................................................................................................101

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.12.1 Variable of the auto memory class.............................................................................101 5.12.2 Variable of the memory class register........................................................................102 5.12.3 Variables, which can be filed in the data range ..........................................................103 5.12.3.1 Global variables and the external-declaration......................................................103 5.12.3.2 static-variables....................................................................................................104 5.12.4 Data type indentifier const..........................................................................................107 5.13 Dynamic memory management .......................................................................................107 5.13.1 calloc.........................................................................................................................108 5.13.2 malloc........................................................................................................................109 5.13.3 realloc........................................................................................................................109 5.13.4 free............................................................................................................................110 5.14 Simple structures..............................................................................................................111 5.14.1 Definition of a structure..............................................................................................111 5.14.2 Declaration of s structure type....................................................................................111 5.14.3 Definition of a structure and simultaneous declaration of the structure type ...............112 5.14.4 Accessing structure elements....................................................................................112 5.14.4.1 The '.' - operator..................................................................................................113 5.14.4.2 The '->' - operator................................................................................................113 5.14.5 Definition of a structure field.......................................................................................113 5.14.6 Initialization of structures ...........................................................................................114 5.15 typedef.............................................................................................................................116 5.16 enum................................................................................................................................117 5.17 File accesses through the FILE-structure..........................................................................118 5.17.1 List of FILE file access functions (incomplete)............................................................118 5.17.2 fopen opens a file....................................................................................................119 5.17.2.1 Particularity when indicating the file name in case of BORLAND-C......................120 5.17.4 fclose closes a file ..................................................................................................121 5.17.5 fflush empties the buffer .........................................................................................122 5.17.6 Character by character reading and writing ...............................................................122 5.17.6.1 Character by character reading ..........................................................................123 5.17.6.2 Character by character writing ............................................................................123 5.17.6.3 The macros getchar / putchar..............................................................................124 5.17.6.4 Resetting characters ...........................................................................................125 5.17.7 Reading and writing strings........................................................................................127 5.17.7.1 Reading strings...................................................................................................127 5.17.7.2 Write string..........................................................................................................128 5.17.8 Formatted reading and writing ...................................................................................128 5.17.8.1 Formatted reading...............................................................................................128 5.17.8.2 Formatted writing ................................................................................................129 5.17.9 Reading and writing block by block ...........................................................................130 5.17.9.1 Reading block by block........................................................................................130 5.17.9.2 Writing block by block..........................................................................................131 5.17.10 Functions for random file accessing ........................................................................132 5.17.10.1 fseek Positioning of the write / read pointer.....................................................132 5.17.10.2 ftell Indicating the position of the write / read pointer.......................................133 5.17.10.3 rewind Resetting the write / read pointer.........................................................134 5.17.11 feof Detecting the file end .....................................................................................134 5.18 Optimized organisation of same type structures................................................................135 5.18.1 Note for examples when using BORLAND-C 3.1........................................................136 5.18.2 Definition of a recursive structure...............................................................................136 5.18.3 Linked lists.................................................................................................................136

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.18.3.1 Simple forward linked list ....................................................................................137 5.18.3.2 Simple backwards linked list ...............................................................................139 5.18.3.3 Double linked list ................................................................................................141 5.18.3.4 Ring link..............................................................................................................144 5.18.4 Binary trees................................................................................................................148 5.18.5 Hashing.....................................................................................................................151 5.19 Bit fields...........................................................................................................................156 5.20 Bit masks..........................................................................................................................157 5.21 Unions (Variants)..............................................................................................................157 6 Some C-library functions...........................................................................................................160 6.1 String processing................................................................................................................160 6.1.1 strcat............................................................................................................................160 6.1.2 strncat..........................................................................................................................161 6.1.3 strchr...........................................................................................................................161 6.1.4 strcmp..........................................................................................................................162 6.1.5 strncmp........................................................................................................................162 6.1.6 strcpy...........................................................................................................................163 6.1.7 strncpy.........................................................................................................................163 6.1.8 strlen............................................................................................................................163 6.1.9 strtok............................................................................................................................164 6.2 Converting character strings to numbers ...........................................................................165 6.2.1 atoi...............................................................................................................................165 6.2.2 atol...............................................................................................................................166 6.2.3 atof..............................................................................................................................167 6.2.4 sscanf..........................................................................................................................167 6.3 Macros for verifying character features ..............................................................................168 6.4 Macros for character conversion.........................................................................................169 6.4.1 tolower.........................................................................................................................169 6.4.2 toupper........................................................................................................................170 6.5 Random numbers generator...............................................................................................170 6.5.1 rand.............................................................................................................................170 6.5.2 srand...........................................................................................................................171 6.6 Program ending..................................................................................................................172

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
2 General considerations regarding C-training The work documentation for the C-training is not suitable for individual study. The lines marked with a bar on the left page margin must be filled in with information obtained during the course. While performing the exercises, you must pay attention to: correct functioning of the program accurate fulfillment of the task simple, well structured and clear program structure the function descriptions, which in some cases must contain the description of the functional interfaces comments for the important program steps (however, not each command must be described) a comfortable user interface The following is valid in principle: better program in a simple and clear way than making it complicated. To make the examples of this script more clear, error handlings were mostly dropped in the program parts. Furthermore, several C-instructions were partly written in a line. You should avoid both in your program!

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
3 C development The B programming language was developed in 1970 by Ken Thompson, in the Bell Laboratories of Murray Hill, to implement the UNIX operating system on a PDP- 7. In 1972 Dennis Ritchie adapted this programming language and enhanced it with the type concept (see "Data types" on page 31). Thereby the language was renamed C. UNIX was written in C and implemented in a PDP-11. C was used a few years only for system programming (operating systems, compiler). C became more important for application programming, which is explained by the portability of the programs. C-programs' portability can however be guaranteed only by standards compliance. Since 1983 there is an ANSI board (American National Standard Institute) working on C standardization. The standardization drafts published in 1988 were extensively used in this document. The upgrade of the programming language C to C++ (a language, which fulfills the requirements of object oriented programming) is not covered in this framework. C should be seen as a subset of C++.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
4 Introduction 4.1 Basic principle of data processing All programs (written in any programming language) work by the same basic principle: Input: certain data is introduced in the program or the program acquires this input data itself. Processing: The data read in during the input is processed and output data is generated. Output: The output data is issued under a certain form. F example E A program should calculate a square root: Input: user introduces a number over the keyboard. Processing: square root is calculated. Output: the square root is written by the program on the screen. F example E A program controls a traffic light: Input: a car drives on a contact loop. Processing: the program determines, that the traffic light for this car can be switched to "green", because no other traffic light shows "green" at the moment. Output: the program switches the traffic light to "green". 4.2 What is a program ? A program is a "cooking recipe" for a computer to perform a certain task (for example square root calculation or traffic light control) input, processing and output. The task of the programmer is to issue such a "cooking recipe".

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

4.3 Program generation with higher programming languages Because the computers themselves only understand a very primitive "language", named machine code, there were higher programming languages developed, which are easier to understand by humans and are more readable than machine code. An instruction in a higher programming language is converted by compiler (a translation program) in many instructions into machine code. 4.4 The shortest possible C-program void main(void) {} Each C-program must have a main program, which is always called main. In this case, this main program receives no parameters when it is started (thus void in the round brackets) and it returns nothing to the operating system, when it is ended (thus the void at the beginning of the line). Furthermore, there are no instructions in the accolades, which could perform the program. 4.5 Simple program with in- and output /* This program calculates the square of a number to be entered and displays the result on the screen: */ #include <stdio.h> void main(void) { int number; /* buffer for number */ scanf("%d", &number); /* input */ number = number * number; /* processing */ printf("%d\n", number); /* output */

} scanf: Function from the standard library for the formatted input of standard
input (see "Input with scanf" on page 45).

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

printf: Function from the standard library for the formatted output on standard output (s. "Output with printf" on page 40). \n: Special character for the output of a new line to the standard output ;:each C-instruction is finished by a semicolon. Text between /* and */: is interpreted by the compiler as a comment and ignored. 4.6 Programs input 4.6.1 The Editor in the integrated environment of BORLAND-C 3.1 4.6.1.1 General There are several methods to activate an open editor window: Clicking press Alt-# (where # is the number of the editor window) select the window of the WindowList dialogue window press or click F6, where the open windows are activated one after another. The active editor window is closed with WindowClose. Press F10, to quit the editor. Before the text can be cut, copied and then inserted again, a block must be marked first. 4.6.1.2 Block commands Function Set block start Set block end Copy marked block at cursor position Shift marked text at cursor position Copy block through clipboard:

Key pressing Strg+K B Strg+K K Strg+K C Strg+K V Strg+Einf Umsch+Einf (at the insertion location)

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Delete block Strg+Entf

4.6.1.3 Editing commands Function Key pressing Del Delete character Backspace Delete character left Strg+Y Delete line Ins Insert ON/OFF 4.6.1.4 Additional commands Function Show last compilation error Show next compilation error Help Help index Full screen Undo Switch to user display

Key pressing Alt+F7 Alt+F8 F1 Umsch+F1 F5 Alt+Backspace ALT+F5

4.6.2 About vi For vi there is a strict delimitation between input mode and command mode: Im the command mode, the user can enter commands like Search or Text Replacement. The user can enter text in the input mode. 4.6.2.1 Calling vi vi <filename> 4.6.2.2 The command mode After calling the vi, you are in the command mode. In the command mode, the cursor can be moved using the cursor keys. The following commands are possible, which must be however entered blind and almost never be confirmed with RETURN.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
When a command was entered, it can be finally repeated by entering a point. 4.6.2.2.1 Moving in the text These commands serve for shifting the cursor mark within the text: 0 $ ^ w b H M L <n>G G Set cursor at the beginning of the line Set cursor at the end of the line Set cursor at the text start of the current line Shift cursor forward by one word Shift cursor back by one word Set cursor on the first position of the first screen line Set cursor on the first position of the middle screen line Set cursor on the first position of the last screen line Set cursor on the first position of the n-th file line Set cursor on the first position of the last file line

4.6.2.2.2 Changing to input mode The following commands are used to change to the input mode (see "The Input mode" on page 18): i I a A o O Insert before cursor position Insert starting with current line start Append after cursor position Append at line end Insert new line under the cursor position and set cursor on the beginning of it Set new line Insert new line through the cursor position at its beginning

4.6.2.2.3 Searching in the text /<text> Search from Cursor forwards to <text>. This command must be quitted with RETURN!! ?<text> Search from Cursor backwards to <text>. This command must be quitted with RETURN!! n Repeat the last search action % Search for the next matching bracket (nesting is considered)

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
4.6.2.2.4 Deletion of text x Deletion of character, upon which the cursor is placed dw Deletion of word, in which the cursor is placed D Deletion of character, upon which the cursor is placed and of all further characters until the end of line dd Deletion of line, where the cursor is placed <n> dd Deletion of n lines starting from the line, where the cursor is placed (the deleted text is stored in a buffer) J Removes the line break of the line, where the cursor is placed the next line is appended to the end of the line, where the cursor is placed. 4.6.2.2.5 Copying of text <n>yy Copies the rest of the line, where the cursor is placed and the next <n> - 1 lines in a buffer p Inserts the buffer content where the cursor is placed

4.6.2.2.6 File insertion :r <filename> :w :w <filename> Inserts the file content <filename> in the place, where the cursor is located. If the vi was started without indicating a file name, then a file can be loaded using this command. Store current file Store current file as <filename>

4.6.2.2.7 quit vi :wq or ZZ :q! Storage of current file and quitting vi quitting vi without storing anything

4.6.2.3 The input mode There are no correction possibilities in the input mode: <BACKSPACE> Deletion of a character left of the cursor

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
<CTRL>U Deletion of line, where the cursor is placed.

Through ESC one can change from input mode to command mode.

Attention M
In some systems, the cursor keys cannot be used during the input mode! 4.7 Pre-processor By calling the C-compiler, a process capable program is generated in several steps from the source program: perform pre-processor instructions translate into machine code (in some systems under certain circumstances through the assembler) Bind, automatic call of binder All pre-processor instructions are marked by the character #, which must be the first visible character (not empty character or tab) of the line. The result file contains no other lines which start with #. The pre-processor instructions have been performed. Pre-processor instructions are finalized through the line end, as opposed to the C-instruction lines. If a line is not sufficient (ex. in case of macro definitions), then the lines, which should have a following line, should be finalized with the \-character (cancellation of Return). 4.7.1 Control of pre-processor function with cc If only the result of the pre-processor instructions should be controlled, then the compiler must be called using the -P switch (see "Calling the CCompiler and the Binder" on page 27).

Example

cc ueb.c -P Result can be found in ueb.i

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
4.7.2 Control of pre-processor function with cpp If only the result of the preprocessor instructions should be controlled, then CPP must be called by DOS-Prompt from the pre-processor, for the respective file. Example cpp ueb.c Result can be found in ueb.i. 4.7.3 Overview of pre-processor instructions #define #undef #include #if #ifdef #ifndef #else #endif symbolic constants (see page 19) and macros (see page 20) Deletes the definition of a previous #define (see page 22) Insertion of files (see page 23) Conditioned translation (see page 24)

4.7.4 Symbolic constants The use of symbolic constants has the following advantages: Programs are easier to modify, because the constant is defined at a central location; a modification of constants concerns only one program line . Programs can be read more easy The names of symbolic constants should always be written in capital letters.

Example
Using the #define NUMBER 100 Instruction, the symbolic constant NUMBER is defined. The pre-processor replaces in the program all NUMBER symbols with the value 100.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
4.7.5 Macros Macros can also be defined using the #define instruction. One or several Cinstructions can be resumed under a macro name. Macro parameters can be agreed. The macro mechanism is a simple text replacement. A text (ex. C instructions) receives a name through the #define - instruction. If this name is called somewhere in the program, then the pre-processor introduces the agreed text there. Example #define NL printf("\n") Call: printf("hello"); NL; printf("how are you"); NL; Example #define MAX(a,b) ((a)<(b)?(b):(a)) Call: var_max = MAX(var1,var2); Example /* Sum of squares: */ #define SQ(x,y) ((x) * (x) + (y) * (y)) Call: erg = SQ(a+b, c+d); Is expanded to: erg = ((a+b) * (a+b) + (c+d) * (c+d)); ttention A The macro parameters should always be included in round brackets in the macro definitions, apart from that, round brackets should comprise the entire macro definition! Here the above example when breaking this rule: /* Sum of squares: */ #define SQ(x,y) x * x + y * y Call: erg = SQ(a+b, c+d); Is expanded to: erg = a+b*a+b+c+d*c+d;

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________ Attention
The current parameters should never receive assignation operators at macro call; for example, the a++ phrase should never be the current parameter of a macro.

Example

/* Square: */ #define Q(x) ((x) * (x)) Call: erg = Q(a++); Is expanded to: erg = ((a++) * (a++)); /* ATTENTION: 'a' is increased twice !!! */ 4.7.5.1 The pre-processor operator "#" The pre-processor operator # triggers, that a macro operator is used as string for the macro expansion. Example #define PR_d(a) printf("%s = %d \n", #a ,a)

Call: int var1 = 4; printf("Result: "); PR_d(var_1); Output: Result: var_1 = 4

4.7.5.2 The pre-processor operator "##" The pre-processor operator ## triggers the connection of the string (mostly assigner of macro operators) to other operators.

Example

#define PR1(p1,p2) printf("PR1: %d\n", p1##p2) #define PR2(p1) printf("PR2: %d\n", var##p1) Call:

int var1 = 100; PR1(var,1); _______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
PR2(1); Output: PR1: 100 PR2: 100 4.7.5.3 Deleting the definition of a previous #define A previously made macro definition or symbolic constant can be reversed again with #undef. This is especially useful, when macros should be used in different contexts. Example #define ERROR \ EXPAND(EVERYTHING_OK,"Everything o.k. !")\ EXPAND(PARAM_WRONG,"Parameters are wrong !") \ EXPAND(PARAM_TOO_LARGE,"Parameters are too large !") /* Generate an enum with the error codes: */ enum { #define EXPAND(code,text) code, ERROR #undef EXPAND NUMBER_OF_ERRORS } error codes; /* Generate a field with belonging error texts: */ char *error text[] = { #define EXPAND(code, text) text, ERROR #undef EXPAND "" /* empty text at the end of the table */ };

4.7.6 Insertion of files

Example

#include " constant.h" The pre-processor replaces the #include-instruction through the content of the constant.h file. Include files can have random content; however, in case of rules they should contain no executable code.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Normally they contain: efinitions of symbolic constants D Macro definitions (see "Macros" on page 20) extern-declarations (see "Global variables and the externdeclaration" on page 113) Structure type agreements (see "Simple structures" on page 122) or typedef-instructions (see "typedef" on page 128) The names of include files usually end with ".h" Should include files be searched by the pre-processor in the current file folder or at a certain path name (personal includes), then the file name must be included in the double high comma. Example #include "beispiel.h" Includes, which lie in the standard include folder of the compiler, must be closed through pointed brackets. Example: #include <stdio.h> 4.7.6.1 Standard path for includes in UNIX systems In UNIX systems the standard folder for includes is for example the /usr/include folder 4.7.6.2 Standard path for includes at BORLAND C For BORLAND C, the standard include path is determined in the normal DOS path (through PATH-instruction). 4.7.7 Conditioned translation #if #ifdef #ifndef #else #endif The conditioned translation is needed to: store different program variants (for example for different HW-environments) in a program, temporarily "delete" program parts (the program parts remain in the program, but they are not also translated),

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
install "switchable" test outputs into the program. Example ... #ifdef DEBUG printf ("Test output: countmax = %d\n", countmax); #endif In this example the program line is deleted with the printf by the preprocessor, this means it is not also translated, if the DEBUG symbol is missing. Program variants can be generated using the #else-instruction. Example The following program fragment displays a text in a outfile file, if FILE is defined, otherwise it shows it on the screen: #ifdef FILE fprintf(outfile,"hello world\n"); #else printf("hello world\n"); #endif Preprocessor operator defined Using the defined pre-processor operator, the existence of several symbols can be verified with a single #if- query. Example #if (defined SYM1) && (defined SYM2) && (SYM3 > 10) Successful test What does the following program display? File: ueb.c #include "ueb.h" void main(void) { #ifdef VARI_1 int var_1 = 1; char var_2 = 'a'; float var_3 = 3.4; #else int var_1 = 2; char var_2 = 'b'; float var_3 = 4.5; #endif PR_icf(var_1, var_2, var_3 ) }

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
File: ueb.h #define VARI_1 #define PR1(var, format) \ printf("%s: %"#format "\n", #var, var); #define PR_icf(p1, p2, p3) \ PR1(p1, d) PR1(p2, c) PR1(p3, f) Hot tip In standard-C, a string can also be indicated in several part strings. For example char *p = "hello " "here " "I am"; triggers the same result as: char *p = "hello here I am"; Result: var_1: 1 var_2: a var_3: 3.400000 4.7.7.1 Symbol generation for UNIX A symbol which can be tested with the #ifdef- or #ifndef-instruction is generated either by a #define-instruction or by the D switch in compiler call (see "Calling the C-compiler and the binder" on page 27). Example cc ueb.c -DDEBUG for compiler call corresponds to: #define DEBUG in the program 4.7.7.2 Symbol generation for BORLAND-C A symbol which can be tested with the #ifdef- or #ifndef-instruction, is generated either by a #define-instruction or by an entry as Defines in the IDE of the BORLAND-compiler

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

4.8 Calling the C-compiler and the binder 4.8.1 cc (Compiler call) Call cc [-<schalter>] <dateiname> Description Calls the compiler and, implicitly, also the binder for the program in the <filename> file. The following steps are made for the compilation: 1. Carry out pre-processor instructions 2. Translate in assembler code. 3. Assemble in object code. 4. Bind to an executable program (see "ld (binder call" on page 28). The data transferred to cc can be: .c (C-source) .s (assembler source) .o (object file) .a (library) cc performs automatically only the necessary translation steps respectively only calls the binder. The most important switches Switches Meaning -c cc only performs the first three steps and generates object modules -S cc only performs the first two steps and generates assembler sources -P cc only performs the first step, only the pre-processor instructions are replaced. This Example cc -c prog1.c prog2.c Output files prog1.o prog2.o

cc -S prog.c

prog.s

cc -P prog.c

prog.i

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
way, the correctness of the pre-processor instructions can be verified. The process capable program is filed as <prgname>. If this switch is dropped, then the program name is a.out Corresponds to a pre-processor instruction in the programm: #define <name> or #define <name> <value>

-o <prgname>

cc prog.c -o prog

prog

D<name> or D<name> = <value>

cc prog.c -o prog

prog

4.8.2 ld (Binder call) Call ld [-<switch>] <file>... [-l<libname>...] Description ld binds the files in the indicated sequence. In addition, object modules from indicated libraries are bound, if an external reference is open on them. ld can only satisfy forward references, this means that the sequence of the modules in the link list is important ! To generate a run-capable program, the first module of the link list must be the runtime start function /lib/crt0.o. This function then calls main(). The most important switches Switch Meaning -s ld removes the symbol table (hinders test)

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
-l<libname> ld searches the libraries /lib/lib<libname>.a or /usr/lib/lib<libname>.a (if the first one does not exist at /lib) for resolution of external references No local symbols are recorded in the symbol table of the output file local symbols are recorded for test purposes Separation of text- and data segment. The text segment is then write-protected and cannot be overwritten by a program error. Output file is <filename>, not a.out

-x -X -n -o<filename >

Example
ld /lib/crt0.o progl.o prog2.o -lc -lffp -o prog ld binds the runtime start function with progl and prog2 and offers the C standard library /lib/libc.a and the C-Library for float arithmetics /lib/libffp.a for resolution of external references. The run-capable program is filed in prog. 4.8.3 ld call through the C-Compiler cc calls ld so that first lib/crt0.o, then the translated modules and the Cstandard library libc.a are bound. ld switches, which are indicated when calling cc, are transferred directly to ld. In addition, the -x switch is valid (no local symbols).

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

5 C speech elements 5.1 Identifier For the name or definition of Constants (see page 35) Variables (see page 33) Functions (see page 94) Identifiers (names, identifier) are necessary. The following rules are valid for these identifiers: they may not contain special characters; exception: underscore they must start with a letter; they should not start with underscore, because this can lead to name misunderstandings in many C compilers. they may consist of capital or small letters Capital- and small letters are differentiated Names for variables or functions are usually written as small letters Names for constants are usually written as capital letters Identifiers are not allowed to be C-keywords Keywords are always written with small letter local identifiers may consist of maximum 31 significant characters. The identifier selection should be made carefully. Program readability is essentially improved, if an identifier gives an indication about the object's function.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

5.1.1 Reserved names / C-keywords / Keywords auto break case const continue default double else enum float for goto int long register short signed sizeof struct switch typedef unsigned void volatile

char do extern if return static union while

Successful test
Mark the wrong and not clearly identifiable identifiers ! Identifier... ...is wrong abc 2_count _begin float multiplication_table Mark100 hundred_thousand_dollar_counter count*2 MINIMAX _1_counter hundred_thousand_marks_counter Wrglgrmpf if_then_else 5.2 Data types Each variable, function or constant must get a certain data type assigned. ...ist correct

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

The basic data types of C are: Characters: char unsigned char signed char Integers: int short long unsigned Floating point numbers: float double long double The representation of individual data type in the memory and thus the numerical range depend on the computer type or the compiler.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

Here as an example the valid data types for the BORLAND C++ compiler 5.0 when using it as 16-Bit compiler: Data type Length in bits Allowed numerical range unsigned char char enum unsigned int short int int unsigned long long float double long double near (pointer) far (pointer) 8 bits 8 bits 16 bits 16 bits 16 bits 16 bits 32 bits 32 bits 32 bits 64 bits 80 bits 16 bits 32 bits 0 to 255 -128 to 127 -32768 to 32767 0 to 65535 -32768 to 32767 -32768 to 32767 0 to 4294967295 -2147483648 to 2147483647 3.4 x 10-38 to 3.4 x 10+38 1.7 x 10-308 to 1.7 x 10+308 3.4 x 10-4932 to 1.1 x 10+4932

The numerical ranges of the individual data types are determined in the Standard-C in the Includes float.h and limits.h. 5.3 Variables Definition of a variable: <type> <name>; When defining a variable there is memory space reserved This memory space gets a symbolic name allocated (variable name). The size of the reserved memory space depends on the data type of the variables. Apart from that, when defining the variables, the validity range within a program and the validity duration is determined. Definition of variables within the validity range of a program and the validity duration is determined. This feature's description follows later. Example

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
int number_1; char zeich;

unsigned marker; double auxiliary counter; Several variables of the same type can be defined in a list. Example int number_1, count, marker; char in_char, out_char; Variables can be initialized when defined. Example int sum = 0 , first = 100; char response = 'n';

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

5.4 Constants Type Int / short Representation decimal octal hexadecimal long decimal hexadecimal float / double4 Example 123 -3 32000 03331 011 0xA0012 0x123F 2345L3 40000L 0x1ffffL 0xlL 3.1415 12.74e-7 -135.76E3 +17E-2 .012e3 'x' 'B' '*' '\n' (newline) '\t' (tab) '\f' (formfeed) '\\' (backslash) '\'' (single quote) '\ddd' (Bit sample in octal representation) '\0' (Bit sample = 0 String end character)

char

1 If 2 If

the first number of an integer number constant is 0, then this constant is an octal number. an integer number constant starts with a 0x or 0X, then it is interpreted as a hexadecimal number. 3 A l respectively L behind an integer number constant marks a constant as long value. 4 Floating point constants are always shown with double exactness

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

Example
Deleting the display and then "hello" output: printf ("\033[2J hello \n\n"); /* For DOS-systems */ printf ("\033[14J hello \n\n"); /* For UNIX-systems */ Example Assigning the ASCII-codes for 'ESC' to a char-variable: char cvar; cvar = '\033'; or cvar = 0xlB; or cvar = 20+7;... 5.4.1 Constant routine A routine which consists only of constant values and operators is already assessed by the compiler (not at runtime). A constant routine can be implemented anywhere there can be constants as well. Example #define MIN 100 #define MAX 1000 .... int middle; middle = (MAX - MIN ) / 2; /* Assignment of a constant expression */ 5.4.2 Boolean constants There is no boolean data type in C; this means variables which can only show the TRUE or FALSE values. These logical values are realized in C as integer constants. Thus the following is valid:

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

0 corresponds to FALSE unequal 0 corresponds to TRUE Example


int comparison; int a = 1; int b = 2; comparison = a < b; if (comparison)....

Successful test
To which data types do the following constants belong? Please also indicate the number representation of the constants if necessary! Constant... 2346 15.026 0x123 0.27E10 2L 'x' 0473 0xABCDL 66899 ...is of the data type:

5.5 In / Output The C language range contains no commands for in/output. This is why each Ccompiler has libraries with its delivery, which make the in/output functions and other functions available. To use most of the I/O-functions it is necessary to draw in a standard

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
include into the C-program. This happens through the following pre-processor instructions at the beginning of the program: #include <stdio.h>

5.5.1 Character by character in/output For a character by character in/output the two macros putchar and getchar are available in C. They are defined in stdio.h. When calling these two macros it is essential to include the stdio.h include! 5.5.1.1 putchar() output putchar gives a character output of the type int on standard output: int putchar (int character); The return value of putchar is the issued character or EOF.

Example
int char = 'a'; putchar(char); putchar(1); char = 0x31; putchar(char); putchar('\6l') putchar('\007'); /* Output of 'char' */ /* Output of '1': */ /* Output of '1' */ /* Output of '1' */ /* Output of octal number 7 corresponds to the ASCII character for alert characters (Beep) */ /* Lead character output for new line */

putchar('\n');

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

List of special character constants \0 ZERO (binary zero 0x00), string end character \x Octal number, where xxx are the digits of the octal number \n New line \f New page \t Tab \b Backspace \' Simple apostrophe \\ Backslash 5.5.1.2 Input with getchar() getchar reads a character of standard input. The read-in character is the return value of getchar. int getchar(void); The return value of getchar is of int type. The content of an input line can only be read out with getchar(), if the line is closed by [Ret]. Each character of the line and the lead character for [Ret] must then be read with a getchar()-call each out of the keyboard buffer.

Example

/* the user needs to give 2 responses */ #include <stdio.h> main() { int response; ........ printf("Do you want to delete? [y/n]: "); response = getchar(); while (getchar() != '\n'); /* Delete keyboard buffer */ if (response == 'j')

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
{

printf("Do you really want to delete ??? [y/n]: "): response = getchar(); while (getchar() != '\n'); /* Delete keyboard buffer */ ........ } } 5.5.2 Formatted in/output 5.5.2.1 Output with printf The standard function printf enables the conversion of numeric values into character representations. The values formatted like that are included into a freely defined text string and displayed upon standard output. printf is also frequently used only for mere text output.

Example

int a = 99; char b = 'A'; printf("This is a test: "); printf("Variable a = %d, b = %c ", a, b); Display output: This is a test: Variable a = 99, b = A 5.5.2.1.1 Sintactic structure of the printf function call printf("Lead character string", arga, argb,.....); The return value of printf is the number of displayed characters or a negative number, in case of error. The control character string contains text to be displayed Formatting specifications for the values to be displayed Lead characters (special character constants).

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

For each format element indicated in the control character string, a value must be transferred as an argument (argn) to printf. This value is converted to printable characters, according to the formatting specification and set on the position in the output text, where the format element in the control character string is located.

The control character string may also contain lead characters, as described at putchar() under "List of special character constants" (see page 39). The type of transferred arguments must fit the formatting specifications. The f and e formats require the transfer of a floating point number! 5.5.2.1.2 Structure of a formatting specification for printf A formatting specification consists of several format elements. The general format of a formatting specification is the following: %<Alignment><Minimum width>.<Width behind point>l<Conversion characters>5

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

5 For

<minimum width> and <width behind a decimal point> a '*' can be indicated, printf then takes the corresponding value out of the argument list. The output field widths are thus variable.

The following table indicates what the meaning of each format element is: Format element Allowed value Meaning % . <Alignment> % Marker for the beginning of a formatting specification The value is displayed leftaligned, the output field on the right is filled with empty characters Right aligned, with leading zeros Left aligned, filled with zeros on the right positive numbers preceded by '+' Right aligned. Rest empty characters Number which determines a minimum field width for the value output. This is used to indicate a value column suitable. If the value output indicates more positions than <Minimum width>, then the output field becomes accordingly wider. Separator, must only be here, if <Width after point> follows. Number which indicates how many digits should appear for the floating point number on

0 -0 + No indication <Minimum width> One or several digit decimal number

. <Width after point>

. one- or several digit decimal number

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
the right of the decimal point or how many characters can be maximum displayed by a character string. The standard for floating point numbers is 6 after-comma positions. The character 'l' indicates, that the belonging argument (the value to be displayed) is of long int type or double. The argument is displayed decimal The argument is displayed octal The argument is displayed hexadecimal The argument must be a float-number; it is displayed in decimal writing (for example 123.456789). If no indication exists on the position of this format element, then the default value of 6 decimal positions is valid. The argument must be a float-number; it is displayed in scientific notation (example -1.234567e+02). The same is valid for the number of decimal positions, as for the conversion characters The argument is displayed as individual character The argument is interpreted as a pointer on a character string. The string is displayed until the text end character ('\0') or until the length, which is determined by <Width

The letter 'l'

d o x f

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
behind point> of the formatting specification.

Example
int var = 0x31; printf("Hello \n"); printf("Now there will be a beep \07 \n"); printf("dez: %d okt: %o hex: %x char: %c", var, var, var, var); /* Output: dez: 49 oct: 61 hex: 31 char: 1 */

Example

double f1 = 1.2; printf("Floating point numbers: %.3f\n %.2e", f1,f1 * 1000); /* Output: Floating point numbers: 1.200 1.20+e03 */

Example with determination of output width (<Minimum width>)


int var1 = 1; int var2 = 2; printf("%10s%10s\n","Column1","Column2"); printf("--------------------\n"); printf("%10d%10d\n", var1++,var2++); printf("%10d%10d\n", var1,var2); /* Output: Column1 Column2 -------------------1 2 2 3 */

5.5.2.2 Input with scanf

scanf is the analogic input function for printf. scanf reads characters
of standard output, interprets then according to the formatting specifications in the control character string and files the resulting values at the addresses, which indicate according arguments.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.5.2.2.1 Syntactic structure of the scanf function call scanf has the same syntax as printf: scanf("Control character string", arga, argb,.....); scanf delivers back the number of successful transformations or EOF. The arguments must be pointer; there are the addresses of the variables, which should be filed in the read-in values. The address of a variable is obtained by the &-operator, for example &var is the address of the variable

var. Example

int ivalue; float flovalue; scanf("%d%f", &ivalue, &flovalue); The control character string contains the formatting specifications. These should be indicated directly one after another. Blanks or another random text would be expected again by the user in the input. 5.5.2.2.2 Structure of a formatting specification for scanf A formatting specification consists of several format elements. The general format of a formatting specification is the following: %<Maximum width>l<Conversion character> The following table indicates what meaning do the individual format elements have: Format element Allowed value Meaning Marker for start of a new % %6 formatting specification. <Maximum width> one or several digit max. character number of input decimal number field. If not indicated, then the input field is read out until the field separation character (Blank (' ') or Ret '\n') or until the next character, which does not fit the conversion character The letter 'l' The letter 'l' indicates, that the l belonging argument (the value to be read in) is of type long int or double. <Conversion d, o, x, f, These conversion characters are characters> e, c7, s possible for scanf

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
(see chapter 5.5.2.1.2 on page 41)

Example

int var_i; float var_f; char var_c; int var_o; scanf("%d%f%c%o", &var_i, &var_f, &var_c, &var_o) ; When entering: 12 3.14a 13 [Ret] The assignment to the following variables occurs: var_i = 12;
6 If

the percent character receives an *, then the input field is read over. For example %*5c reads over 5 characters. 7 With the format c, several characters can be read in. The maximum character number is indicated before c. The read in character sequence is not finished with the string end character in case of the c-format Blanks can only be read in using the c-format.

var_f = 3.14; var_c = 'a'; var_o = 11; /* octal: 13 */ Example int a,b; double f; char y, feld[20], z[2]; scanf("%3d%x%1lf%c%*5d%4s%1s", &a, &b, &f, &y, &feld[0], &z[0]); When entering: 298 12ab 7612345 Wort i The following assignment occurs to the variables: a = 298; b = 4779 (0x12AB); f = 7.0; y = 6; 12345 is read over feld[0] = 'W'; feld[1] = 'o'; feld[2] = 'r'; feld[3] = 't'; z[0] = 'i';

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

scanf leaves the line end \n in the keyboard buffer; this one must first be cleaned of the following scanf-calls first, using getchar. scanf ignores inputs, which only consist of \n, if the format element is not %c. Successful test What does the following program display ? The user introduces: This is the data [RET] 19 33 45 1 [RET] Here is the program: #include <stdio.h> void main(void) { int varl, var2, var3; unsigned varl; char zeich; while ((zeich= getchar()) != 0x20) putchar (zeich); printf(" Result:\n"); while (getchar() != '\n'); /* Deletion of keyboard buffer */ if ( 4 != scanf("%d%d%d%d", &varl, &var2, &var3, &var4)) { printf ("wrong input \n"); } else { varl += -var2++ + --var3; printf("varl: %d var2: %d var3: %d\n", varl, var2, var3); var4 *= 16; printf("var4: %x\n",var4); varl = var2 == var3; var2 = ++varl + var4; printf("varl: %d var2: %o\n",varl, var2); } } Solution: var_1: 30, var_2: 34, var_3: 44 var_4: 10 var_1: 1 var_2: 21

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

5.6 Operators and routines 5.6.1 Overview of operators in C Simple assignment operator (see page 49) arithmetic operators (see page 50) Comparison operators (see page 51) Logic operators (see page 52) Operators for Bit-Manipulation (see page 53)

a = b; x = a + b * c; if (a > c)... if (a && b)... x = a & b;

5.6.2 C - Specialties Compound assignment operators (see page 54) Increment / decrement - operators (see page 55) Determining the size of types and variables in bytes through sizeof (see page 56) Conditioned routines8 (see page 56)

a += b; a--; sizeof(int); (a>b)?(max=a): (max=b);

5.6.3 Simple assignment operator The operator (variable) left of the equal sign gets the value of the routine on the right of the equal sign assigned. The routine is thus automatically converted into the data type of the target variables.

Example

int var_1; float target; var_1 = 11; target = var_1 / 3;

/* => target is 3.0 */

Also an assignment is a routine and delivers back a value; this value can for example be transferred during a function call as parameter: float var_2; var_1 = funk_xyz (var_2 = 100); /* =>> the function parameter is of float type and has the value 100.0 */ Apart from that, multiple assignments are possible through the named feature:

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

var_1 = var_2 = var_3 = 0; 5.6.4 Arithmetic operators Addition Subtraction Multiplication Division Modulo-division

+ * / %

Example

int varl = 1; int var2 = 3; float var3 = 1.2; char var4 = '\03'; int result; result = (var1 + var2) / 2 /* 2 */ - var3 * var3 /* 1.44 */ + var4 % 3; /* 0 */ Total result is 0 !! For the sequence of a routine assessment, see at "Priority and assessment of operators" on page 57. 5.6.5 Comparison operators They compare their operators regarding their numerical values. The result of this comparison is a logical value. The logical values TRUE and FALSE are demonstrated in C by integer numbers (int). Thus the used numerical value is compiler dependent under certain circumstances. Thus for working with logical values with the help of the C-pre-processor, the symbolic names TRUE respectively FALSE are recommended to be defined. For this purpose, the following instructions are necessary at the beginning of the program or in a central Include: #define TRUE (0 == 0) #define FALSE (0 == 1) Comparison operators are:

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Equal Unequal Greater than Greather than or equal Less than Less than or equal == != > >= < <=

Example

if (a >= b).... while (sum != MAX).... log_erg = (a == b); if (log_erg) ....

Attention !!!
The assignment operator "=" is often mistaken for the assignment operator "==". The instruction if (a=b)... assigns a the value of b; the value of b is also interpreted as a logical value and leads in the if-query to the corresponding program jump. For the sequence of assessing an expression see at "Priority and assessment of operators" on page 57. 5.6.6 Logical operators AND OR Negation && || !

These operators determine the truth value of the operators and deliver after a logical connection of the operators a truth value. Thus the following is valid for the operators' content: 0 corresponds to FALSE

unequal 0 corresponds to TRUE


The result of a logical connection corresponds to that for the comparison operators (see "Comparison operators" on page 51).

Example _______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
if ( (a > MIN) && (a < MAX))... /* The condition is TRUE, if also a is greater than MIN as well as less than MAX */ while (!flag) . . . /* The loop is ran through for as long as the content of the variable flag FALSE is */ if ((sum == 0) || (sum == MAX))... flag_a = (flag_b && flag_c);

5.6.7 Operators for Bit-manipulation Bit-wise Bit-wise Bit-wise One's complement Left-Shift Right-Shift AND & OR EXCLUSIVE-OR ^ ~ < >>

These operators can of course not be used with the floating point numbers. The right-shift-operations should be used as much as possible only with the variables of the 'unsigned' type, because otherwise a machine dependent leading sign handling occurs. This can lead to the fact, that either zeros are traced from the left side (logical shift) or the one's complements are traced from the left side (arithmetic shift). This is also valid for char-values ! In case of unsigned-variables, zeros are drawn in each case. A left shift draws a zero, in each case.

Example

model_1 = model_in | 0x0f; var = var & ~077;

/* The lower value four bits are set */ /* The lower value six bits are reset. */

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

/* Additional comparison: var & 01777700 is machine dependent; assumes, that int assigns two bytes. */ unsigned value; value = value >> 2; /* the content of the value is shifted to the right by 2 bit positions */

Attention !!!
The operators for bit by bit AND/OR-connection are often mistaken for the operators to the logical AND/OR-connection: logical connection: (1 && 2) gives 1 and(1 || 2) gives 1

bit-by-bit connection: (1 & 2) gives 0 and (1 | 2) gives 3


5.6.8 Compound assignment operators The programing practice often needs instructions of the following type: y = y <operator> x;

Example
y = y + x; C allows here a more compact writing type: y <operator>= x; For the example: y += x;

The following compound assignment operators are available: += -= *= /= <<= >>=

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
&= |= ^=

Example
var1 *= var2 + var3 * 2; corresponds to var1 = var1 * (var2 + var3*2); value /= divisor; rest %= 3; model <<= 3; model <<= mask; device_status |= 0x0f; flags ^= comparison model; 5.6.9 Increment and decrement operators An often used instruction, the increase or reducing of the content of a variable by 1 can be simply realized in C through the increment- / decrement operators. ++ Increment -- Decrement Examples: index++; corresponds to index = index + 1; respectively index += 1; count--; corresponds to count = count - 1; respectively count -= 1; The increment-/decrement operators can be indicated before or after the variables. 5.6.9.1 Prefix quote

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
When indicating the operator before the variables, then the variable is first incremented or decremented and then inserted in the routine. Example value = 1; var = 2; xyz = 3; value += var * ++xyz; value = 9; var = 2; xyz = 4; 5.6.9.2 Postfix quote When indicating the operator after the variables, then the variable in the routine is first inserted and finally incremented (decremented) Example value = 1; var = 2; xyz = 3; value += var * xyz++; value = 7; var = 2; xyz = 4; The increment/ decrement operators are often used in connection to field-or loop-indexes. 5.6.10 sizeof The sizeof-operator determines the size of an object in bytes. The result of the sizeof-operator is of size_t type. This type is determined in the include file stddef.h. The object can be: variable a a field a structure the name of a data type (also typedef-agreements) Example printf("allocate int-numbers %d Bytes",sizeof(int));

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.6.11 Conditioned routines Conditioned routines represent a compact writing type for the assessment of conditions. Syntax <condition>?<true_routine>:<false_routine>; First <condition> is assessed. If the routine is TRUE then <true_routine> is the result of the conditioned routine. If <condition> FALSE, then <false_routine> delivers the result of the conditioned routine. Example success = ((turnover - costs) > 0) ?GOOD:BAD; If the condition "(turnover - costs) > 0" is fulfilled, then the symbolic constant GOOD is assigned to success, otherwise success receives the content BAD. The conditioned instruction replaces simple if-queries: if ((turnover - costs) > 0) success = GOOD; else success = BAD; 5.6.12 Priority and assessment of operators The sequence with which the individual operations of a routine are performed, is determined in the following table: Highest priority Conclusion () [] -> . From the left ! ~ ++ -- - (<typ>) * & sizeof From the right * / % From the left + From the left << >> From the left < <= > >= From the left == != From the left & From the left ^ From the left | From the left && From the left || From the right

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
?: = += -= etc (see "Simple assignment operator" on page 49 and "Compound assignment operators" on page 54) lowest priority From the right From the left

Hot tip
It is better not to learn this by heart - the compiler can master these priority sequences very easily, but the programmers always make mistakes. The safe method is to set brackets where you can, because this way the intentions are absolutely clear.

5.6.13 Routines A routine is a construction of operands, operators and round brackets. A routine always delivers a value. Thus the routine var = 100 does not only allocate the variable var the value 100, but delivers itself the value of 100. A routine can thus be found everywhere, where the resulting value matches, like for example as an argument to a function. Example double value, res; ...... res = sqrt(value = 2); ...... 5.6.14 Side effects in routines Through function calls, nested allocations and the increment / decrement operators, the variable contents can be modified during the processing of a routine (so-called "side-effects"). If a routine causes side effects, then the sequence in which the values are stored (compiler dependent!) can be crucial for the result. Example for routines, which should be avoided Example Example a = 3;

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
z = a / ++a; a = 3; z = a / (a + 1); a++;

Would be better

It is not defined, when the value for "a" is taken from or stored into the respective memory cell; the example thus shows surely, whether the dividend is 3 or 4 (compiler dependent!).

Example
Example Would be better a b a c b a = = = = = = 4; (( a = 3) * (a *= 3)); 3; a * 3; a * c; c;

Variable a has either the value of 9 or the value of 12. The variable b has either the value 27 or 36. Example Example Would be better x = y = a = ++x x = y = b = ++y a = ++x z++; z = 1; || ++y && z++; z = 1; && z; || b;

Routines with logical operators (&& or ||) are assessed from the left to the right until the truth value is agreed. As soon as the result of the logical routine is agreed, the assessment is interrupted. Thus in the above example, the variables y and z were never incremented. The highest priority of && to || is not important here!! Another example: x = 0; y = 1; z = 1; a = x && (y++ || z++); y and z were also not modified here !

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.6.14.1 Rules for avoiding side effects In conclusion, the following rules must be set up: if an assigment to a variable appears in a routine, then this variable is not allowed to be used a second time in the routine.

in routines with logical operators, the integrated assignments should be avoided. (The increment / decrement operators imply an assignment to the variable!!) ! Successful test Answer the questions in the comment lines of the final C program ! It is assumed, that for the used compiler TRUE is set as 1 and FALSE as 0! void main(void) { int value_l, value_2, value_3, value_4; value_1 = -20 / 4 + 2 * 4; /* what does value_1 contain ? */ 3 value_1 *= 3 + 2; /* what does value _1 contain? */ 15 value_1 += value_2 = value_3 = 4; /* what do value_l, value_2 and value_3 contain? */ 19, 4, 4 value_1 = value_2 == value_3; /* what do value_l, value_2 and value_3 contain? */ 1, 4, 4 value_1 == (value_2 = value_3 + 1); /* what do value_l, value_2 and value_3 contain ? */ 1, 5, 4 (value_1 gets nothing assigned !) value_1 = 1; value_2 = 2; value_3 = 0; value_4 = value_1 || ! value_2 && value_3; /* what does value_4 contain? */

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
1 value_1 = 1; value_ = 2; value_3 = 3; value_2 += -value_1++ + ++value_3; /* what do value_l, value_2 and value_3 contain? */ 2,5,4 value_1 = 5; value_2 = value_3 = 4; value 4 = ((value_1 >= value_2 >= value_3) ? 1 : 0 ); /* what does value_4: contain ? */ 0 } 5.7 Control structures 5.7.1 Blocks Agreements and instructions are gathered to a block using accolades. This is used to: define a function body, conclude several instructions depending on if, while and for . After the right accolade, which closes a block, there is never a semicolon at least not in C and except for structures (see "Simple structures" on page 122) 5.7.2 if-branching 5.7.2.1 General form of the if-branching Syntax if (<routine>) <instruction_1>; else <instruction_2>; The routine <routine> closed in brackets, which follows upon if is assessed. If the routine gives a value unequal 0 (TRUE), then

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
<instruction_1> is performed. If the routine gives 0 (FALSE), then <instruction_2> (of the else-branch) is performed. If more than one instruction must be performed in a branch, then the instructions must be summarized to a block.

5.7.2.2 if-instruction without else-branch The else-branch of an if-instruction can be missing: if (<routine>) <instruction_1>; <instruction_2>; In this case <instruction_l> is performed, if <routine> is TRUE, in the other case, the program is immediately continued with <instruction_2>. 5.7.2.3 Nested if-instructions if-instructions can be nested; thus it must be considered, that an else-instruction always belongs to the previous if, for which there is no else-part yet. Example if (a > b) if (c > a) max = c; else max = a; Should anything be modified in this allocation of else-instruction, then this is reached through blocking: Example if (a > b) { if (c > a)

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
max = c; } else max = b; 5.7.2.4 else-if-chains If a decision must be taken from several alternatives, then this will happen through else-if-chains.

Syntax if (<routine_1>) <instruction_1>; else if (<routine_2>) <instruction_2>; else if (<routine_3>) <instrucion_3>; else <instruction_4>; etc. Example /* Function: The program reads a temperature value from standard input and gives according messages regarding the status of water in case of this temperature */ #include <stdio.h> void main(void) { float temp; printf("Please enter temperature: "); scanf("%f",&temp); if (temp <= 0) printf("\n the water is frozen \n"); else if (temp == 4) printf("\n at this temperature the " "water is liquid and has the " "highest density \n"); else if (((temp > 0) && (temp < 4)) || ((temp > 4) && (temp < 100)))

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
printf("\n the water is in liquid " "state\n"); else if (temp == 100) printf("\n the water is boiling\n"); else printf("\n steam is forming\n"); } 5.7.2.5 Some common errors when handling if-queries Attention If there is a semicolon behind the if-routine indicated in the brackets, then only an empty instruction is performed instead of <instruction_1> (common error source !). Attention Another common error source is, that an if-structure in the code is however correctly indented in the code, but it is written syntactically incorrect. This error is easily overseen when reading the program listings. False if (<routine>) <instruction_1>; <instruction_2>; In this case <instruction_2> is always performed.... true if (<routine>) { <instruction_1>; <instruction_2>; } In this case <instruction_2> is only performed, if <routine> is true.

Attention In the C-programs, a numeric verification to 0 respectively unequal 0 is often replaced by the logic interpretation of the value: if (var) instead of if (var != 0) if (!var) instead of if (var == 0) Because this clearly deteriorates the program's readability, this bad habit should be avoided as much as possible.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.7.3 switch-instruction 5.7.3.1 Basic form of switch-instruction Using the switch-instruction it is checked, if the result of a routine matches with one of several constant values. Syntax switch (<routine>) { case <const_l>: <instructions_1>; break; case <const_2>: <instructions_2>: break; .... default: <default_instructions>; break; } The <routine> of the switch-instruction is assessed and compared with the case- constants <const_1>, <const_2> etc. The case-constants must either be of int or char type. Of course there can also be constant routines. If a match is found: (<routine_n> == <const_n>) Then the instructions <instructions_n> are performed up to the next break-statement or the end of the switch-blocks. If no match is found, then the <default_instructions> are performed until the next break-statement or the end of the switch-block. If default is missing, then nothing will be done. Attention The sequence of the case-branches and the default-branch has nothing to do with the sequence in which the comparison of <routine> with <const_1>, <const_2> etc. occurs. Even if default is at the beginning, all comparisons are performed ! Example /* Function: The program reads a number between 1 and 6 as a note of standard input and displays the corresponding conversion of the note on standard output: */ #include <stdio.h>

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
void main(void) { int note; printf("\n please enter note:"); scanf("%1d",&note); switch (note) { default: printf("\n Input error \n"); break; case 1: printf("\n very good \n"); break; case 2: printf("\n good \n"); break; case 3: printf("\n satisfactory \n"); break; case 4: printf("\n sufficient \n"); break; case 5: printf("\n poor \n"); break;

case 6: printf("\n insufficient \n"); break; } }

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.7.3.2 Variant with partly missing break-instructions If break is missing as a finalization of the case-instructions, then the program flow runs in the instructions of the next case. This feature is necessary to be able to summarize several case-instructions with the same program handling. Attention This is an often error source. Example switch(note) { case 1: case 2: case 3: printf(" this note is ok \n"); break; case 4: case 5: case 6: printf(" this note is not " "acceptable \n"); break; default: printf(" input error \n"); break; Successful test Explain the function of the following program! Give an example for the program flow!

#define EXIST_MIN 1000 #define EXIST_GUT 10000 #include <stdio.h> void main(void) {

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
int salary; char category; printf("\nenter monthly salary: "); scanf("%d",&salary); printf("\n %20s %20s %20s\n", "daily salary", "monthly salary", "yearly income"); printf(" %20d %20d %20ld\n", (salary/30), salary, salary*12L); if (salary < EXIST_MIN) { printf("\nYou are a poor bastard \n"); category = 'a'; } else if (salary > EXIST_GOOD) { printf("\nYou are to be envied \n"); category = 'r'; } else { printf("\nYou don't have to die of hunger \n"); category = 'm'; } switch(category)

{ case 'a': printf(" Money alone does not make one " "happy \n");

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
break; case 'r': printf(" Money has no smell \n"); break; case 'm': printf(" Christmas comes but once " "a year \n"); break; default : printf(" this cannot be\n"); break; } } Solving the successful test The program displays the daily salary calculated from the read in montly salary and the yearly income with two comment lines. The user is prompted to enter by the message Enter monthly salary : Input: an integer number (-32768 to +32767) Thus the daily salary, the entered monthly salary and the calculated yearly income, calculated from the entered monthly salary, are displayed in columns with a corresponding title. After the output of an empty line, the output of a 2-line comment regarding the salary occurs. In addition, the entered salary is classified into one of 3 categories: Category 'a': salary < EXIST_MIN Category 'm': EXIST_MIN <= salary <= EXIST_GOOD Category 'r': salary > EXIST_GOOD Example: Enter monthly salary: 900 Daily salary monthly_salary yearly-income 30 900 10800 You are a poor bastard Money alone does not make one happy 5.7.4 while loop

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.7.4.1 Standard form of a while-loop Syntax while (<routine>) { <instruction>; /* Loop body */ } <routine> is assessed before each loop runthrough. The loop is only ran through, if <routine> displays a value unequal 0 (TRUE). If the loop body consists only of one instruction, then the blocking can be renounced to ({}). Example /* The program displays a conversion table of Fahrenheitto Celsius temperatures on the standard output. It starts with 0 F and ends with 300 F; the increment is 20 F. */ #define LOWER 0 #define UPPER 300 #define STEP 20 void main(void) { float celsius; int drive = LOWER;

while (drive <= UPPER) { celsius = (5.0 / 9.0) * (drive - 32.0); printf("%4d %6.1f \n", drive, celsius); drive += STEP; } }

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.7.4.2 while-loop with empty loop body The loop body can however remain empty: /* Emptying of keyboard buffer: */ while(getchar() != '\n'); Attention An often error cause is the accidental setting of a semicolon Behind the bracketed while-routine. It can easily come to endless loops. 5.7.5 do - while loop Syntax do { <instruction>; } while (<routine>); For the do-while-loop, the loop condition <routine> is checked after each loop run-through. If <routine> gives a value unequal 0 (TRUE), then the loop is rant through again. The loop body is thus processed at least once. The do-while-loop is used much more rarely than the whileloop. It is used if a loop must be ran through at least once.

Attention
As opposed to the while-loop, the semicolon is necessary behind the bracketed do-while-condition. Example /* At least 1 character is read in by the standard input. The character is displayed again on standard output. The reading in is interrupted if a '#' is entered. */ ..... do {

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
char = getchar(); putchar (char); } while ( char != '#'); 5.7.6 for loop Syntax for (<routine_l>; <routine_2>; <routine_3>) { <instruction>; } If the loop body consists only of one instruction, then the ({}) blocking can be missing. The three routines of the for-loop have the following meaning: <routine_l>: Loop initialization; usually initialization of run variables. <routine_2>: Run through condition of loop; the routine is assessed before each loop run-through. If it shows a value unequal 0 (TRUE), then the loop is ran through. <routine_3>: Re-initialization of loop; actions, which must be performed for each loop run-through; normally incrementing or decrementing the run variables. Example /* The program displays a conversion table of Fahrenheitto Celsius temperatures on standard output. It starts with 0 F and ends with 300 F; the increment is 20 F. */ #define LOWER 0 #define UPPER 300 #define STEP 20 void main(void) { float celsius; int drive = LOWER; for (drive = LOWER; drive <= UPPER; drive += STEP) { celsius = (5.0 / 9.0) * drive - 32.0); printf("%4d %6.1f \n", drive, celsius);

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
} } Each of the three routines can be missing. If for example <routine_2> is missing, then the result is an endless loop. Example for ( i = 0;; i++) { field[i] = getchar(); if (field[i] == '*') break; } or: for (;;) { char = getchar(); putchar(char); } The endless loop is also often realized by: while (TRUE) { .... } <routine_1> and <routine_3> can consist of several instructions, which are separated by a comma. Example for (i = 0, k = 0; i < MAX; i++, k += 2) { field_1[i] = field_2[k]; /* Each second element of 'field_2' is transferred to field_1 */ }

/* This condition... */ /* ...leads to the interrupt of the endless loop */

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

5.7.7 break- instruction The break-instruction leads to leaving the inner loop (while, do-while or for-loop) or leaving a switch-block. In case of switch-blocks (see "switch-instruction" on page 65) the breakInstruction is indispensable. For loops, break mostly serves for making the loop condition more visible. Example for (i = 1; i < 20; i++) { if ((i % 5) == 0) break; printf("%d ",i); } printf("\n"); /* Output: 1 2 3 4 */

5.7.8 continue - Instruction The continue-instruction forces the interruption of a loop run-through. For while- or do-while-loops, the loop condition is assessed and processed in the TRUE-case of the next loop run-through. In case of for-loops, <routine_3> is performed, <routine_2> is assessed and in case of TRUE the next loop run through is started. The continue-instruction can not be used, to quit switch-blocks. Example for (i = 1; i < 20; i++) { if ((i % 5) == 0) continue; printf("%d ",i); } printf("\n"); /* Output: 1 2 3 4 6 7 8 9 11 12 13 14 16 17

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
18 19 */ 5.7.9 goto - Instruction / Brands Syntax ..... goto <mark>; <instructtion_x>; ..... <mark>: <instruction_y>; When reaching the goto-command, the wird die <instruction_x> instruction is not performed anymore; instead it is jumped to mark <mark> and the <instruction_y> instruction is the next to be performed. The use of the goto-instruction is only allowed, if for example several nested loops must be quitted instantly, to initiate an error handling, for example. For brand names, the same rules are applied as for variable names. Brands do not need to be extra defined. The goto-instruction should be used as rarely as possible !!!!! Example: while (....) { for (...) { for (...) { ..... if (catastrophe) goto error; ..... } } } ..... error: printf("catastrophe !!! \n");

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

5.8 Data type conversions 5.8.1 The implicit conversion of the data type In C there is the possibility to link operands of different data types with each other. Different rules for implicit type conversion are applied then. Rule 1: The "lower" type with the lower bit width is converted into the "higher" type with the higher bit width. char/shortintlongfloatdoublelong double The result of a routine always receives the operand type with the highest bit width. Example int z1 = 30000, z2i = 30000; long z2l = 30000; long erg1, erg2; erg1 = z1 + z2i; printf("erg1: %ld \n", erg1); /* Error due to int-overflow:"erg1: 5536" */ erg2 = z1 + z2l; printf("erg2: %ld \n", erg2); /* Addition with longExactity:"erg2: 60000" */ Rule 2: During assignment, the result of the routine on the right of the assignment operator is converted into the type of the target variables. Modern compilers generate a warning in case the type of the target variables is not able to record the routine result with full accuracy. Example int full; full = 20.0 / 3.0; printf(" %d \n", full); /* output: 6; BORLAND

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
- Compiler generates a warning "Conversion may lose significant digits" */ char c; c = 0; /* instead of "c = '\0' */ Rule 3: Floating point calculations are always performed with double exactness. 5.8.2 The explicit conversion of the data type If the rules of the implicit data type conversion are not sufficient, then there's the possibility of the explicit type conversion with "Casts". A "Cast" is a type designation set in brackets, which precedes the operand. Syntax (<Type designation>)<routine> The cast determines the routine type. The cast operator has lost significance due to the introduction of function prototypes in Standard-C. (Function prototypes enable an implicit type adaption of the parameters) Example float value; int number; .... printf("(int) value: %d\n", (int)value); printf("number/2: %f\n", ((float)number)/2); Example long result; int number1, number2; .... result = ((long) number1) * number2;

Attention
Carelessly set casts bring more programming errors than any other construct! The reason is, that a cast is a type of agreement declaration of the programmer in regards of the compiler, to handle a routine in a certain way this way all type

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
verifications are thwarted by the compiler! 5.9 Fields (Arrays) 5.9.1 Unidimensional errors To access a group of same-type elements in an efficient way, these objects are gathered in a field. Definition of a field <typedesignation> <fieldname> [<number_of_elements>]; Example /* Definition of a field, which consists of 100 intelements: */ int field[100]; The field size indicated in a field definition must be a constant routine ! The elements of a field could be: scalar objects of all types other fields (see "Multi dimensional errors" on page 80) Structures (see "Definition of a structure field" on page "125) Unions (see "Unions (Variants)" on page 174) Pointers (see "Pointer fields" on page 93) Example char c_field[SIZE * 2]; float flo_field[FLOAT_NUMBER]; Field elements are handled as individual variables of the according data type. An element is accessed using an index. The index is indicated in square brackets after the field name.

Attention
The index runs from 0 to field size minus 1 !! By selecting an unallowed index it is immediately possible to destroy other variables or even program parts of the memory.

Example
#define C_NUMBER 10 /* Important ! Field size ALWAYS define centrally

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
! */ char c_field [C_NUMBER]; int i; for (i = 0; i < C_NUMBER; i++) c_field[i] = 'a'; /* all elements of the field are to be allocated with 'a' */ The elements of a field stand one after another in the memory! 5.9.2 Multidimensional fields Multidimensional fields are defined by listing the individual dimensions one after another in square brackets. Example Example for a field, which should assimilate the characters for an output field of 5 columns and 2 rows. Row 1 should contain numbers ranging from 0 to 4, row 2 should have numbers from 5 to 9:

'0' '5'

'1' '6'

'2' '7'
5

'3' '8'

'4' '9'

#define ROWS 2 #define COLUMNS char c = '0'; int i, j; for (j = 0; j < { for (i = O; i < output [j][i] =

ROWS; j++) COLUMNS; i++) c++;

The memory allocation for this example looks like the following: Address Content Symbol adr 0x30 output[0][0] adr+1 0x31 output[0][1] adr+2 0x32 output[0][2] adr+3 0x33 output[0][3] adr+4 0x33 output[0][4] adr+5 0x33 output[1][0]

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
adr+6 adr+7 adr+8 adr+9 0x33 0x33 0x33 output[1][1] output[1][2] output[1][3] output[1][4]

Hot tip
To be remembered: the last index is the fastest to run through.

5.9.3 Initialization of fields at definition Fields can be pre-allocated with values already during definition; in this case, an additional code must be written, which pre-allocates the fields with meaningful values. The initial values are 1. separated by commas, 2. included in accolades and 3. attached through an allocation marker to the array definition. Example int turnover[5] = {1000, 1100, 2000, 3500, 7000}; Example float threshold_values[] = {12.5, 120e-2, 0.4, 3.5e03}; The field size is determined according to the number of initial values; here: 4. Example char output[2][5] = {{'0', '1', '2', '3', '4'}, {'5', '6', '7', '8', '9'}};

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

The accolades which include the row elements are there to give a better overview and are not obligatory. Example char errmessage[] = {'f','a','l','s','c','h','e',' ', 'E','i','n','g','a','b','e','\0'}; simply: char errmessage[] = "wrong input"; /* Exception: characterFields can be initialized With character strings without accolades. */ 5.10 Pointer The handling of pointers is essential in C philosophy. Due to their outstanding meaning in C programming it is necessary to deal with pointers for a long time. Attention Pointers can also be misused and they can include errors, which are very hard to find. The following must be valid when handling pointers: to be used there, where they are necessary, however under no circumstances where they are unnecessary! Pointer types usually appear with Function parameters (see "Function parameters as an address ("call by reference")" on page 100), Fields (see "Pointers and Fields" on page 87), Structures (see "The '->' - operator" on page 124) and dynamic memory (see "Dynamic memory management" on page 118) The pointer concept is relatively easy to understand for assembler-programmers because: A pointer is a variable, which contains the address of another variable. A variable can be accessed indirectly using a pointer.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.10.1 Definition of a pointer A pointer must be agreed with the target object type. It is defined by setting a star * before the name. Example int *intpol; /* Definition of a pointer on an intvariable */ /* Definition of a pointer on a charvariable: */ char *char_poi; 5.10.2 The address of a variable The address of a variable is received by indicating the address operator & before the variable name. Example int var, *var_poi; /* The pointer "var_poi" gets the address of "var" assigned: */ var_poi = &var; 5.10.3 The content of a memory cell addressed over a pointer The content of a variable named over a pointer is reached with the help of the indicating operator '*' (referencing). The variable can be read or modified this way. Pointers with the '*'-operator can appear in routines, wherever there can be simple variables found as well. Example int var_1, var_2, *var_poi; var_poi = &var_1; *var_poi = 9; var_2 = *var_poi; /* works like: var_1 = 9 */ /* works lile: var_2

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
= var_1;*/ /* works like: var_1++; here: Needs brackets */ /* works like: var_1 = var_1 * 2; */

(*var_poi)++;

(*var_poi) *= 2;

5.10.4 Example of a memory allocation with variables and pointers Memory content according to the following instructions: int x = 1; int y = 2; int z = 3; int *point_y, *point_z, **point_point_z; point_y = &y; point_z = &z; point_point_z = &point_z; Variable x y ... z Point_y ... Point_z ... point_point_z Address 1000 1002 ... 7000 7002 ... 9100 ... 9200 Memory content 1 2 ... 3 1002 ... 7000 ... 9100

If a pointer (for example in a function) can get no defined value assigned, then it should never be left with a random content (points to a random location) . For this case, there is the zero pointer ZERO defined in the standard-include stdio.h. Example

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
if (error) poi = ZERO;

5.10.5 Pointer arithmetics Pointers can also be used to do arithmetic operations; this is necessary if the pointer must indicate to other variables, for each calculation. Allowed operations with pointers: Addition of an integer number value (int-routine) int wert = 3; poi += value; /* poi is further positioned by 3 elements */ Increment poi++; Subtraction of an integer number value /* poi is positioned back by two elements: */ poi -= 2; Decrement poi--; /* poi is positioned back by one element */ Subtraction of two pointers of the same type. By subtraction a number is determined, which corresponds to the number of elements between the two pointers plus 1. The result is thus an int-number. number = point_1 - point_2; /* number = Number of elements between the two pointers plus 1 */ Comparison between two pointers. Pointers can be compared with the following comparison operators: >

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
>= < <= == != Example number = (point_x > point_y) ? (point_x- point_y): (point_ypoint_ x); Successful test What does the following program display on standard output ? #include <stdio.h> void main(void) { int number_1, number_2, number_3, *pointer, *pointer; number_1 = 5; number_2 = 9; pointer = &number_3; *pointer = number_1 + number_2; printf(" %d \n", number_3); /* 14 */ pointer = &number_l; number_1 = number_2 * number_3; printf(" %d \n", *pointer); /* 126 */ number_2 = *pointer / 2 * 7; printf(" %d \n", number_2); /* 441 */ (*pointer)--; printf( " %d \n", number_1); /* 125 */ zeiger = pointer; printf(" %d \n", --(*zeiger)); /* 124 */ }

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.10.6 Pointers and fields Pointers and fields are strongly connected in C. Each operation with fields can also be formulated with pointers. The field name without index is a pointer on the first element of the field. Also valid for multidimensional fields! In a field int field[10]; if field is a pointer on field[0]. Example 3 possibilities of allocating a field with 0. int field[10]; int i; /* 1. Possibility: */ for (i = 0; i < 10; i++) field[i] = 0; /* 2. Possibility: */ for (i = 0; i < 10; i++) *(field + i) = 0; /* 3. Possibility: */ int *poi; for (poi = field; poi < (field + 10); poi++) *poi = 0;

5.10.6.1 Connection between physical address and pointer arithmetics The pointer arithmetic goes depending on the memory necessity of the addressed object. A pointer on a field element is set when incrementing on the next field element. Example float *flo_po; flopo++;

/* The flopo pointer is further positioned by 4 Bytes */

int *i_po; /* The i_po pointer is further positioned by 200 bytes:

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
*/ i_po += 100;

5.10.7 char - pointer (Strings) A special use of char-pointers are the "character-strings" (string literals, character strings). The content of a character-string is a sequence of characters which is limited by the limit character '\0'. When defining char-fields, which should take up a character string, it must be considered, that: Field length = number of characters +1 limitation character The type of a string is: char-field, initialized with the characters, which are closed between high commas. Because the char-field has no name in this case, the string itself is a char-pointer! It is shown by a character string closed between double apostrophes. Strings are used as: Function parameters (see "Strings as function parameters" on page 89) Assignment to char-pointers (see "Strings in assignments to charpointers" on page 90) Initial values for char-fields (see "Strings at the initialization of char fields" on page 91) 5.10.7.1 Strings as function parameters In the previous examples strings were used in case of printf function calls. The instruction printf("hello"); transfers to the standard function printf the string "hello" respectively a pointer on the character string h, e, 1, 1, o, \0 "hello" is a char-pointer The instruction printf(" %s %s %s", "hello", "halli", "helau"); transfers thus to the function printf four char-pointers. The first pointer addresses a character string, which contains the formatting characters; the

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
following three pointers are the strings to be displayed (the format element %s requires an address as a corresponding parameter!).

5.10.7.2 Strings in assignments to char-pointers A char-pointer can get a string assigned during definition or during the program flow. Example char *cpoi; c_poi = "hello\n"; printf(cpoi); Example Initialization of a field of char-pointers char *t_zeit[] = {"Morning", "Noon", "Evening", " Night" }; Thus a field of char pointers is made, which point out to the indicated strings.

Zeit = time Morgen = morning Mittag = noon Abend = evening Nacht = night

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
There are different possibilities to access the strings Example /* output: noon: */ printf("%s\n", *(t_zeit +1)); /* output: noon: */ printf("%s\n", t_zeit[1]); /* output: n: */ printf("%c\n", *(*t_time+2)+3)); /* outout: n: */ printf("%c\n",*(t_time[2]+3)); 5.10.7.3 Strings when initializing char-fields char-fields can only be initialized at string definitions; Allocations during the program flow are not allowed. Example char c_field[6] = "Hello"; char message[] = "wrong input";

5.10.7.4 Standard functions for string handling Several functions are available in the C standard library for handling character strings (see "String processing" on page 177).

Examples
#include <string.h> char *target, *source; char *str1, *str2; strcpy (target, source) strcpy(cfe, "Hello"); strcat (target, source) Copies the source string to the address, which indicates target. Copying is ended through the string end character '\0'. Appends the source string to the target string

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
strncat (target, source, length) strcmp(str1, str2); the source string is appended with length Byte respectively until the string-final character to the target string. Compares str1 with str2 character by character, according to the ASCII-character set and delivers the following values back : 0 if str1 == str2 >0 if str1 > str2 <0 if str1 < str2 Searches in the string transferred in str1 for the indicated characters (here: c). The search starts at the beginning of the string.It is ended at the first appearance of the c character or at the string end character '\0'

strchr(str1,'c');

Example

char *src, *dest; /* Formation of strcpy-function */ /* src the pointer should be on Source-String,*/ /* dest the pointer should be on target string */ while ((*dest++ = *src++)

!= '\0'); 5.10.8 Pointer errors Pointers can be gathered in a field. 5.10.8.1 Definition of a pointer field int *poifeld[3]; /* defines a field of 3 intpointers */ 5.10.8.2 Assignment of an address to a field element poifeld[i] = &var; /* corresponds to *(poifeld +i) = &var; */

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

5.10.8.3 Access to an addressed object *poifeld][i] = 0; /* corresponds to **(poifeld+i) = 0; */ The name of a pointer field is like in other fields, a pointer on the field element 0; in case of pointer fields, it is thus a pointer on a pointer. 5.10.9 Pointer on pointer Pointer on pointers are especially used in parameter transfer to functions (see "Argument transfer to the main-function" on page 101). 5.10.9.1 Definition int var, *poi; int **point_point; 5.10.9.2 Allocation point_point = &poi; 5.10.9.3 Access *point_point = &var;

/* simply referenced According to.: poi = &var; */ /*double referenced corresponds to var = 100 or *poi = 100; */

**point_point = 100;

Successful test What does the following program display? #include <stdio.h> int field[10] = {1,2,3,4,5,6.7,8,9,10}; void main(void) { int *poi, **poipoi, i; poi = field;

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
poipoi = &poi; for (i=0;i <5; i++) { printf(" %d", **poipoi); poi += 2; } } Result: 1 3 5 7 9 5.11 Functions Functions enable the separation of a complex program into individual manageable units. In general, C-programs consist of several small functions and not a few large functions. C-programs can be divided into several source files. The source files are translated separately; the resulting object modules are set and bound in libraries, if necessary. In the present examples and exercices there were some functions called already and always a function which defines the main-function. The called functions were functions from the standard library like for example printf() or scanf().

5.11.1 Function definition The function definition consists of the function head which describes the function type, function name and the parameters, and contains the function body, Which has the definition of the local variable and the instructions of the function. Syntax <type> <functionname> (<parameter>) { <local symbols> <instructions> } Description <typ>: This name indicates the type of the function's return value; this means the type of routine, which is located in brackets behind the return-instruction. (see "Result transfer through the return value"

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
on page 99). If the type name is missing, then the int type is taken as a default value. If a function delivers no return value, then it should be defined with the void type! <functionname>: the same rules apply for function names as for variable names. <parameter>: The parameter list is indicated in brackets behind the function names. The parameters are indicated with their type; they are separated by comma. Parameters can be missing; in this case, the keyword void is indicated in brackets behind the function. Example float flo_funk(int p1, int p2) { float xyz; xyz = (float)p1 / p2; /* float-cast float-Division */ return xyz; } 5.11.2 Function call A function is called by indicating the function name and through the current parameters listing, which is included in round brackets. A function call can be found everywhere, if a function returns a value where a variable or a constant of the same type could be found. If a function delivers no value back, then the function call must be an indivicual instruction. The current paramteters for the function call must correspond regarding the number and type with the formal parameters of the function definition (see also "Parameter transfer" on page 99). Example int var_1, var_2; float erg; erg = flo_func(var_1, var_2); Example value = func(a,b) * 100; printf("Result: %d", func(value,200)); func_x(value1, value2); func_x(func(a, b), value2);

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

Function definitions cannot be nested. Functions can of course be called as nested. Example void sendling(void), laim(void); void main(void) { printf("vor Sendling\n"); sendling(); printf("behind Sendling\n"); } void sendling(void) {

printf("in Sendling\n"); printf("before Laim\n"); laim(); printf("behind Laim\n"); } void laim(void) { printf("in Laim\n"); } Output: before Sendling in Sendling before Laim in Laim behind Laim behind Sendling

Functions are usually global objects. They can be called by any random program part, even if the source-programs can be found in different files.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
By indicating static before the type-name respectively before the function name, the validity of a function can be limited to a file, where the function is defined. The function name is not communicated to the linker in this case. 5.11.3 Function declaration Before it is called, a function is declared with number and type of parameters. Example extern float frechen( int argl, double *arg2); an external function, which delivers back a float-value; the first argument is of int type. The second argument is a pointer on double. Example extern char *cfunk(void); an external char-pointer-function without parameter (a function, which delivers back a char-pointer). Example int xprintf(const char *format, ...); an internal int-function with a constant char-pointer (string) as first parameter and a random number of the following parameters. The function prototypes of all standard functions are available in the includes. The name of the corresponding include is indicated at the function description in the compiler handbook. Before the function type at a function declaration, the keyword external is given, if the declared function is not defined within the same file. Example Declaration, calling and definition of a function float flo_func(int, int); /* Function declaration */ void main(void) { .... value = flo_func( var_1, var_2); /* Call */ .... }

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
/* Function definition, if necessary in another file */ float flo_func (int p1, int p2) { float value; ... return(value); } 5.11.4 Result transfer through the return value A function can return one(!) value to the calling program using the returninstruction. This value is indicated in the return-instruction. The type indicated at the function definition must match with the type of the return value. Example char resp[21]; char * hol_antw(void); void main(void) { .... printf ("Response: %s ", hol_antw ()); } char *hol_antw(void) { printf("Please enter response (max " "20 characters: "); scanf("%s",response); return(response); } 5.11.5 Parameter transfer The actual parameters of the function call should match regarding numbe rand type of formal parameters of the function definition. A standardC-compiler can only perform a type test and automatic type adatption of the parameters, if the function was declared with a function prototype.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
For standard functions, the corresponding prototype include should be included for this reason. Parameters can be values ("call by value") or addresses ("call by reference").

5.11.5.1 Type test of parameters under UNIX A type test of parameters enables however the syntax checker lint under UNIX. 5.11.5.2 Function parameters as value ("call by value") Values are transferred to the function. The function can return no result through the "call by value" parameter. 5.11.5.3 Function parameters as address ("call by reference") An address (pointer) is transferred to the function as a parameter. Through this address, input values can be transferred to the function or return values received from the function. Fields can only be transferred through address parameters to the function. Example /* The content of the fields "field_1" and "field_2" should be exchanged; the "exchange" function is called for this purpose, which receives the start addresses of the fields and their length as parameters */ /* Function declaration: */ int exchange(char *p1, char *p2, int p3); char field_1[] = {'1', '2', '3', '4', '5', '\0'}; char field 2[] = {'a', 'b', 'c', 'd', 'e', '\0'}; void main(void) { printf("%s \n", field_1); printf("%s \n", field_2); if ( exchange(field_1, field_2, sizeof(field_1))) printf("Fields exchanged \n");

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
else printf("Error \n"); printf("%s \n", field_1); printf("%s \n", feld_2); } int exchange (char *adr1, char *adr2, int number) { int i; char between; if (number <= 0) return(0); /* no exchange possible */ for (i = 0; i < number; i++) { between = *(adr1 + i); /* Exchange */ *(adr1 + i) = *(adr2 + i); *(adr2 + i) = between; } return(1); /* Exchange ok */ Output 12345 abcde Fields exchanged abcde 12345 5.11.6 Argument transfer to the main-function A C-program can receive arguments transferred when calling. Syntax void main(int argc, char *argv[]) or int main(int argc, char *argv[])

Description The argument transfer occurs through a parameter transfer to the main-

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
function. Thus, this function is the only function which can have none or two parameters. The main-function can access the transferred data through the two parameters argc, argv. WIth these two parameters the main-function is always called. In case of the present examples for the definition of the mainfunction, these parameters were ignored. The formal parameters of the mainfunction can of course have random names. The names argc and argv are however usual and should be kept. The main-function can be of the type int or void. If the main-function is of int type, then it should deliver a return value back to the calling program (operating system). If the returnInstruction is missing, then the return value is undefined. Meaning of parameters of the main-function argc: int-value, which indicates the number of arguments in the command line. The program name is thus the first argument and is also counted by argc for this reason. argc has thus at least the content 1. argv: Pointer on a field of char-pointers. These pointers contain the start addresses of the argument string indicated at the program call. These strings are character strings divided by separation characters (Blanks, Tabs). Example For defining a main-function with argument transfer: Definition of the main-function /* File: ueb.c */ void main( int argc, char *argv[]) { int i; for (i=0; i< argc; i++) printf("\n Argument %d %s",i,argv[i]); } Program call ueb hello how are you

Output

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Argument 0 : ueb Argument 1: hello Argument 2 : how Argument 3 : are you It must be considered, that the transferred arguments are always in the character string. Should they be interpreted as numbers, then the strings must be converted with the help of standard functions. Example for calling the standard function atoi. The function atoi() converts a string into an int-value. The parameter at atoi() is the start address of the string to be converted: the return value is the resulting int-value. char string[] = "1234"; int value; value = atoi(string); corresponds: int value = 1234; Example printf("Argument 1 + Argument 2 = %d \n", atoi(argv[1]) + atoi(argv[2])); 5.11.7 Pointer on functions In C you can define pointers on functions. The address of a function can thus be given for example to another function as a parameter; apart from that, function tables can be realized. 5.11.7.1 Definition of a function pointer <Rtyp> (*<Fpointer>)(<ParFunc>); Where Rtyp is the type of return value of the function, on which the function pointer should indicate Fpointer is the name of the function pointer ParFunc are the parameters of the function, on which the function pointer should indicate.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

Example char (*funcpoint)(void); defines a pointer, on a function named funcpoint, which receives no parameters (void) and has a return value of char value. 5.11.7.2 Assigning a function's address The address of a function is the function name without brackets. Example Assuming there's a function declared: char char_func(void); The address of this function is assigned to funcpoint like the following: funcpoint = char_func; 5.11.7.3 Calling the function through the function pointer char value = (*func_point)(); Example Calling functions through a function pointer field: void funcl(void), /* Declaration of functions */ func2(void); #include <stdio.h> void main(void) { int input; /* Def. a field of function pointers: */ void (*func_poi[2])(void); /* Assigning the function addresses To the pointer: */ func_poi[0] = func_1; func_poi[1] = func_2; printf("Please enter function number [1/2] "); scanf("%d",&input); /* Call one of the two functions depending on the read-in number: */ (*func_poi[input - 1])(); }

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
void func_1(void) { printf("\n here is function 1 \n"); } void func_2(void) { printf("\n here is function 2 \n"); } 5.11.7.4 Sorting of fields with "qsort" A special use of function pointers is the use of the library function qsort. Syntax #include <stdlib.h> void qsort(void *base, size_t nelem, size_t width, int (*fcmp)(const void *, const void *)); Description Sorts the elements of an array with the help of the Quicksort algorithm. qsort calls repeatedly the comparison function fcmp defined by the user for this purpose. base points to the first element (0) of the array to be sorted; nelem contains the number of elements to be sorted; width indicates the size of an individual element (in bytes). fcmp takes over the two arguments elem1 and elem2. Both are pointers to the elements of the array. The comparison function compares the two elements (*elem1 and *elem2) and delivers an integer value as a result: *elem1 < *elem2: Return value < 0 *elem1 == *elem2: Return value = 0 *elem1 > *elem2: Return value > 0 For the comparison, the less-than symbol (<) means that the left positioned element should appear before the right positioned element when sorting. Analogical, the greater-than symbol (>) means, that the element positioned on the left should appear after the element positioned on the right in the sorting. Return value None.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Example #include <stdio.h> #include <stdlib.h> #include <string.h> int i_field[5] = {674,-646,9387,23876,-563}; char c_field[5][30] = {"klsdjfh","wrelkjh","lkiewrj", "aKJHFUR","krewaj"}; float f_field[5] = {3.15, 0.814, 47.11, 386436.97, -12.3}; int i_comp(const void *a, const void *b) { return (*(int *)a - *(int *)b); } int c_comp(const void *a, const void *b) { return strcmp((char *)a,(char *)b); } int f_comp(const void *a, const void *b) { if (*(float *)a > *(float *)b) return 1; else if (*(float *)a < *(float *)b) return -1; else return 0; } void main(void) { int i; /* Sortieren: */ qsort(i_field, 5, sizeof(int),i_comp); qsort(c_field, 5, sizeof(char[30]),c_comp); qsort(f_field, 5, sizeof(float),f_comp); /* Output: */ printf("\nInt-Field sorted:\n"); for (i=0; i< 5; i++) printf("%d\n",i_field[i]); printf("\nString-Field sorted:\n"); for (i=0; i< 5; i++) printf("%s\n",c_feld[i]); printf("\nFloat-Field sorted:\n"); for (i=0; i< 5; i++) printf("%f\n",f_field[i]); }

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.11.8 Recursive function call C-functions can be called recursively; this means that a function can call itself directly or indirectly. With the help of these functions, applications which work with recursively defined data structures (for example tree structures) can be implemented more simple and comprehensible. It must be considered that recursive functions require a lot of memory space and time. At each function call, all local data are agreed and the memory place is allocated. The end of the recursion must be programmed carefully! Example Calculating the faculty #include <stdio.h> long facul(int pl); /* Declaration of function to calculate the faculty */ void main(void) { int number; printf("Faculty of: "); scanf("%d", &number); printf("\n %d! = %ld \n",number,facul(number)); } long facul(int until) { long erg; if (until > 0) /* recursive function call: */ erg = bis * facul(until -1); else erg = 1; return(erg); } Example Digit string of standard input to be read into a field The lowest value digit should be filed in the first field element. For example input: 903 field[0]= 3, field[l]= 0, field[2]= 9

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
#include <stdio.h> #define MAX 10 /* maximum length of Digit string */ /* Function for recursive read-in of digits: */ void read(char *field, int *i); void main(void) { char field[MAX]; /* target field for the reversed digit sequence */ int i; /* Field index */ i=0; read (field, &i); /* Read in digit sequence */ } /* read: Read in standard input digits. Interrupt at 'Return'. File read-in digits in opposite sequence starting with 'adr' => the last read-in digit is filed in the field[0l. 1. Parameter: Start address of "char"-field 2. Parameter: Address of an "int"-variable, which is used as field index; must containt the value 0 at the first 'read'Call */ void read(char *adr, int *i) { char c; /* "Over" the recursion */ if ((c=getchar())

== '\n') return; /* Reversal of recursion at line end */ /* read-in character is filed on the "Return" of the recursion in 'feld': */

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
read (adr,i); /* read in next character */ /* "Return" of recursion: */ if (*i == MAX) return; /* Error: the first entered digits go lost, because there were more digits entered than maximum allowed */ *(adr+*i) = c; /* file the character read in on the "to-way" of the recursion in the field */ (*i)++; /* Increase field index */ } 5.11.9 Complex definitions In case of complex data definitions, the following notions must be differentiated: <type> <name>[] <name> is an "Array of <type>" <type> *<name> <name> is a "Pointer to <type>" <type> <name>() <name> is a "Function returning <type>"

Example /* "clist" is an "array of (right before left) pointer to char": */ char *clist[3];

Example float *(*ffunc[5])(); /* array of pointer to function returning pointer to float */

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.12 Memory classes Each variable is assigned to a certain memory class. The memory class determines the validity range, the validity duration and in some cases the initialization of a variable. The memory class of a variable is determined at definition, by the position of the definition of indicating the control words static or register. Validity ranges can be: a block a function all functionen in a file entire programm Validity duration can be: Program flow within a block Program flow within a function entire program flow For the examples up-to-now, only variables of the auto Memory class were used. 5.12.1 Variable of the auto memory class Definition type: Validity range: Validity duration: Features: Definition of variables at the start of a block without indicating a memory class The block, where the variable was defined Program flow from entry until leaving the block, where the variable was defined. The variable is assigned with its initial value at each block entry, if it was defined with an initialization. This value can be dynamic; for example the result of a function. If auto-variables are not initialized explicitly, then they have a random content. auto-variables are applied at the stack. This must be considered, if for example large fields or structures of the memory classe auto lead to a stack overflow.

Example #include <stdio.h> int func(void) {

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
return 1; /* trivial function... */ } void main(void) { int value = func(); printf("value: %d \n",value); { int value = 2; printf("value: %d \n", value); } printf("value: %d \n",value); } Output: value: 1 value: 2 value: 1

5.12.2 Variable of the memory class register register-variables are a special type of auto-variables. They are filed, as far as possible in the processor registers. If in a block there are more registervariables defined than there are processor registers available, then the rest of the variables are applied as normal auto-variables. The use of register-variables can shorten the program runtime in case of frequence accessing. Only variables of the data type long, int, unsigned, char (integer number variables) can be defined with the memory class register. Definition type: Validity range: Validity duration: Features: Definition of variables within a block and indicating the control word register before the type indication. The block where the variable was defined Program flow from entry until exiting the block, where the variable was defined. The variable is assigned with its initial value at each block entry, if it was defined with an initialization. This value can be dynamic; for example the result of a function.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
If register-variables are not initialized explicitly, then they have a random content. Example register int x; register char c; 5.12.3 Variables, which can be filed in the data range 5.12.3.1 Global variables and the external-declaration Type of definition: Definition outside any block limit (also function block) without indicating a memory class. Validity range: global, in each function; also in functions, which were defined in another file. Validity duration: Total program runtime Features: Global variables are filed in the program data range; thus they get a fixed memory space assigned (as opposed to the auto-variables on the stack). The variable is allocated only once with its initial value, at program start should it be defined with an initialization. The initial value must be a constant expression. If global variables are not initialized explicitly, then they are pre-allocated with zero. The variable name is communicated to the linker, This way functions which are defined in other files can access the variable. This only requires an external-declaration. The external-declaration To access the variables, which were defined in another file, this variable must be communicated with an external-declaration. With this declaration, the compiler is communicated the type of these global variables and there is an external-marker entered on the variable for the linker. Block rules are valid for the declaration, this means that the variable can only be used in the block where it was declared. If the declaration is outside any block limit, then the variable is valid in all functions, which are defined in the file. For a variable there can only be one definition but as many declaration as desired. A variable must be either defined or declared before it is used.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

Example /* File: main.c */ /* Definition of global variables: */ int glob_var; /* Declaration of a function: */ extern void func_x(void);

int main(void) { ... glob_var = 1; func_x(); ... } /* File func.c */ /* Declaration of variables: */ extern int glob_var; void func_x(void) { ... printf ("glob_var: %d \n", glob_var); ... } 5.12.3.2 static-variables Type of definition: Within a block or outside any block by showing the keyword static. Validity range: In the block, where the variable was defined respectively in all functions of the file, if the variable was defined outside any block limit. Validity duration: Total program runtime Features: static-variables, which were defined outside the block

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
limits, differ from global variables only by the fact, that the variable name is hidden before the linker. Functions which were defined in other files cannot access staticvariables. Thus it should be worked according to the rule, that there should be as little data as possible generally available. static'-variables, which were defined within a block limit ' differ from the auto-variables by the validity duration. Because static-variables are valid during the entire program runtime, functions can be developed with "memory". static-variables are only allocated with their initial value once at program start. The initial value must be a constant routine. Example /* The program reads in from the user a 4-digit secret number. The user has 3 trials to enter the correct secret number. In case of successful entry, the function 'all_ok' is called; after 3 faulty inputs, the function 'alarm' is called */ #define TRUE (1==1) #define FALSE (O==1) #include <stdio.h> static int input; /* for entering the secret number */ int secret(void); /* Function for read-in and testing of the secret number */ void main(void) { int i; for(;;) { printf("please 4-digit secret number " "enter"); scanf("%4d",&input); if (secret()) { all ok(); break;

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

} } } int secret(void) { /* The next variable counts how many times 'secret' was called in a comparison cycle */ static int secret_count = 0; /* Secret number: */ int secret_nr = 1234; if (input == secret_nr) { secret_count = 0; return(TRUE); } else { if (++secret_count >= 3) { alarm (); secret_count = 0; } return(FALSE); } }

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.12.4 Data type indentifier const Using the const keyword before a variable definition it is agreed, that this variable cannot be modified. Thus it cannot be positioned on the left of an assignment character. (Error message: no lvalue or lvalue required) Use Declaration of function parameters: agreement, that a transferred parameter is not allowed to be modified in the function. Only valid for pointer transfer ! (Callby-reference). ROM-data: data, which cannot be modified physically (like for example the content of an EPROM). partly write-protected data in shared-memory-systems. Example const int var1 = 100; /* The next function declaration determines, that the transferred string is not modified: */ int funk (const char *message); 5.13 Dynamic memory management For program variables there are the following filing possibilities in the memory: Variable types local variables static, global variables Dynamic variables Memory Stack, register Data range of program Dynamic memory (heap) Assignment of... Compiler Compiler Compiler or operating system

The number and size of the necessary memory space ranges is often unknown at the moment of programming. In order not to request the maximum necessary memory space for the program each time, there is the possibility of dynamic memory request. This way, the additionally needed memory is requested (or allocated) from the operating system during runtime. The available dynamic memory range is also called "heap". The variables which are filed in the dynamic memory are valid independento of the block structure, until the program end or until the explicit release by the program.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
The functions described in the following paragraphs are available for managing the dynamic memory. 5.13.1 calloc Syntax #include <stdlib.h> void *calloc(size_t nitems, size_t size); Description calloc allows access to the C Heap. The heap is available for dynamic allocation of memory blocks of variable size. Many data structures like trees and lists use memory allocation on the heap. calloc allocates a block of the size nitems * size. The entire block is set to 0. Return value calloc returns a pointer to the newly allocated block. If there is not enough memory space available or either nitems or size equal zero, then calloc returns ZERO. Because the returned pointer is of type void *, it must normally be recasted to the desired data. Example #include <stdio.h> #include <stdlib.h> #include <string.h> void main(void) { char *str = ZERO; /* Allocated memory for 10 chars: */ str = (char *) calloc(10, sizeof(char)); /* Copy "Hello" in this memory block: */ strcpy(str, "Hello"); /* Show string at: */ printf("String is %s\n", str); /* Release memory again: */ free(str); }

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

5.13.2 malloc Syntax #include <stdlib.h> void *malloc(size_t size); Description malloc works like calloc, except for the following: Only the number of necessary bytes is transferred in the size parameter. The memory is not initialized with zeros Due to these reasons malloc usually works faster than calloc. Return value malloc returns a pointer to the newly allocated block. If there is not enough memory space available or size equals zero, then malloc returns ZERO. Because the returned pointer is of void * type, it must usually be recasted to the desired data type. Example float *ffield; ... /* A float-field of the size 'fnumber' is applied: */ ffield = (float *)malloc(fnumber * sizeof(float));

5.13.3 realloc Syntax #include <stdlib.h> void *realloc(void *block, size_t size); Description realloc tries to increase of diminish a previously allocated memory block to size Bytes. If size is zero, then the memory space is released and ZERO is returned. The block parameter points to a memory block previously allocated with calloc, malloc or realloc.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
If block equals ZERO, then realloc works just like malloc. realloc modifies the size to the allocated memory block to size, by copyind the content into a new memory block, as far as necessary. Return value realloc returns a pointer to the reallocated memory block, which differs from the pointer on the initial block. If the memory block cannot be reallocated, then ZERO is returned. If size equals zero, then the memory block is released and realloc returns ZERO. Example long *lo; ... /* A long-field of the 'lnr' size is allocated: */ lo = ((long *)malloc(lnr * sizeof(long)); ... /* A larger field is necessary (new size: n_lnr): */ lo = (long *)realloc(lo, n_lnr * sizeof(long));

5.13.4 free Syntax #include <stdlib.h> void free(void *block); Description free releases a memory block again, one that was allocated by calloc, malloc or realloc through a previous call. Thus it is again available for further reservations. Return value None. Example char *buffer; ...

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
/* A char-field is applied for 'c_size' characters: */ buffer = (char *)malloc(c_size * sizeof(char)); ... /* The char-field is not necessary anymore: */ free(buffer); 5.14 Simple structures A structure comprises variables of different data types. The elements of a structure could be: Variables of the basic data types (see "data types" on page 31) Pointer (Pointer) (see "Pointer (Pointer)" on page 82) Fields (Arrays) (see "Fields (Arrays)" on page 79) other structures, bit fields (see "Bit fields" on page 172), Unions (see "Unions (Variants)" on page 174) Pointer on structure of the same structure type (see "Definition of a recursive structure" on page 150) Structure fields (see "Definition of a structure field" on page 125) can be defined. 5.14.1 Definition of a structure Example struct { char product[20]; int performance; int capacity; float price; } vehicle; The vehicle structure is defined and thus also the memory space allocated. This structure contains a char-field. vehicle.product is the start address of this field. Apart from that, the structure contains the int-variables vehicle.performance and vehicle.capacity, as well as the floatvariable vehicle.price. 5.14.2 Declaration of s structure type Example struct appointment { int year;

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
char month[10]; int day; int hour; int minute; }; A structure type appointment is agreed. No structure is defined! No memory space is allocated! Structures can be defined with the help of structure types.

5.14.3 Definition of a structure and simultaneous declaration of the structure type Example struct broadcast { char title[40]; struct appointment start; struct appointment end; } news; The structure news is defined. This structure contains the elements: news.title, news.start.year, news.start.month ... news.end.minute Additionally, the structure type of the broadcast name is given. 5.14.4 Accessing structure elements

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.14.4.1 The '.' - operator Individual structure elements are accessed with the point operator. Example Struct appointment practice; practice.hour = 12; practice.minute = 10; 5.14.4.2 The '->' - operator The elements of a structure, which is addressed through a pointer can be accessed with the arrow operator. Example int func_x(struct appointment *prac) {

... prac->hout = 12; prac->minute = 10; strcpy(prac->month, "September"); ... } The elements of a structure addressed through a pointer can be accessed also as usual, with the help of the "*"-operators (not usual). Example (*prac).hour = 12; (*prac).minute = 10; strcpy ((*prac).month, "September"); 5.14.5 Definition of a structure field Structure fields are used, like other fields, if several same type structures should be managed and handled together in a program. Because we will learn later about other organisation types (see "Optimized organisation of same type structures" on page 149), we must set here the following advantages and disadvantages of structure fields:

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Advantages of structure fields Fast access to elements of structure fields is possible, as far as the index is sufficient as a selection criteria for the structure field element to be addressed. Structure fields contain no overhead to form organisation. Disadvantages of structure fields Structure fields of variable size can be realized through dynamic memory management (see "Dynamic memory management" on page 118), but the insertion or deletion of individual elements is slow and complicated. Sorting of structure fields is slow, because the entire contents of the structure field elements must be copied again. Insertion or deletion of individual elements of a structure field and keeping a sorting is only possible through time consuming copying. Example struct broadcast program[20]; /* a field is defined , which contains 20 Structures of the type 'broadcast'. Example of a Structure element: program[ 3].start.hour */ 5.14.6 Initialization of structures Structures are initialized with the same rules as fields; the initial values are indicated in accolades after the definition Example struct art { int number; char *name; float weight; float price[2]; } article = {10, "squid", 2.25, {30, 67.5}}; Successful test

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
What does the following program display? struct nixfix { char *str; int nr; struct nixfix *spoi; }; void main(void) { struct nixfix abc [] = { {"aaa", 1, abc+1}, {"bbb", 2, abc+2}, {"ccc", 3, abc } }; struct nixfix *poi; int i; poi= abc; printf("\n %s %s %s \n", (poi++)->str, abc[2].spoi->str, abc[0].str); printf(" %s %s %s \n", (poi--)->str, abc[1].str, abc[1].spoi->str); for (i=0; i< 6; i++) { printf(" %d", ++(poi->nr)); poi = poi->spoi; } printf("\n"); } Solution: aaa aaa aaa bbb bbb ccc 2 3 4 3 4 5

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.15 typedef Some type names can be introduced with the help of the typedef keyword. A synonym for an already existing data type is created. No new data type is defined! typedef is often introduced by standard functions. The corresponding typedef instructions are then available in standard-includes (mostly in stdlib.h or stddef.h). typedef is entered to: improve the readability of programs (a complicated data type Is hidden behind an easy to understand name) improve the portability of programs (a system dependent data type can be "exchanged" at a central location) Example typedef char *string; /* The next definition corresponds to: char *lines[LINES]; */ string lines[LINES]; Example typedef struct { char name[20]; int age; float salary; } person; person headcount[P_NUMBER]; Example In the following example the current time is determined and displayed on standard output. The representation of time instruction is hidden behind the type name time_t. The belonging typedef-instruction is located in the standardinclude time.h.

#include <stdio.h> #include <stdlib.h> #include <time.h> void main(void) { time_t t;

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
if (-1 == time(&t)) /* acquire current time */ error(TIME); else printf(ctime(&t)); /* prepare time instruction and display */ } 5.16 enum Enumeration data types can be defined using the enum keyword. When defining such a data type, the value range is defined by listing all possible elements. Hot tip It is recommended to used only comparison operator and instructions for enum type variables, but no arithmetic operations. Example enum stoplight { green, yellow, red }; This defines a new data type stoplight. Variables of this data type are allowed only to accept the indicated values green, yellow or red. Example enum stoplight a_road1; a_road1 = red; The countup values are assigned increasing values starting with 0; this way, in the above example green gets the value of 0, yellow the value of 1 and red the value 2. This standard value assignment can be varied: Example enum direction { north = 0, east = 90, south = 180, west = 270 }

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
orientation; 5.17 File accesses through the FILE-structure For the file access, there are functions of the C-standard library used. These functions access the files buffered, with the help of the FILE-structure. Advantages: portable programming efficient file access through buffered reading / writing. Data blocks are not taken individually from the disk or written on it but buffered in their "normal size" (for example 512 Byte sector length) in the memory. By reducing a disk access, the file access times can be reduced considerably. The FILE-structure is defined in the standard-include <stdio.h> through a typedef instruction. If a program uses the file access functions of the C standard library, then this include must be also incorporated. The FILE-structure is applied when opening the file; it contains information, which is necessary for the buffered writing / reading of the file.

5.17.1 List of FILE file access functions (incomplete)

Name fopen freopen fclose fflush getc, fgetc putc, fputc fgets fputs fscanf fprintf fread fwrite fseek

See page 131 133 134 134 135 136 140 141 141 142 143 142 145

Function Opening a file Closing a file Character by character input Character by character output String by string input String by string output Formatted input Formatted output Block by block input Block by block output Help functions for random access (Random

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
ftell rewind feof 147 147 148 Access) File end recognition

5.17.2 fopen opens a file Syntax #include <stdio.h> FILE *fopen(const char *filename, const char *mode); Description Opens a file, which is defined by the file name filename and allocates a FILE structure to it. fopen returns a pointer, which is used to create a reference for this file in the following file operations. The number of open files is limited.

Three FILE objects are automatically generated at program start. They can be used through the FILE-pointer with the following symbolic name (without previous fopen!): stdin stdout stderr for standard input for standard output for standard error output

In the string mode the type of file opening is determined: r Open file for reading (read) w Open file for writing (write). If a file with this file name already exists, then this file is overwritten. a File for appending (append) opened at file end; if the file does not exist, then the same as in w is performed. r+ Open an existing file for revision (simultaneous reading and writing). w+ Open a new file for revision (simultaneous reading and writing); if a file with

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
this name already exists, then it is deleted. a+ Open a file for revision (simultaneous reading and writing) at the file end (append) respectively, if it does not exist, generate it. If it is to be indicated that a file should be generated or opened in the textmode9, then a t must be appended at the mode string (for example rt or w+t etc.) The same way, a b must be appended, if a generation or opening of a file is desired in the binary mode10. If a file is opened for revision then input- as well as output operations can be performed on it; but an input cannot occur immediately after an output, without fseek or rewind being called at least once in the meantime, an output cannot occur immediately after an input, without fseek or rewind being called at least once in the meantime or the input has reached End-offile.

9 Textmode:

In the text mode, the character string CR (Carriage Return) and LF (Line Feed) is translated in a single LF during read-in. In case of output, an individual LF is converted in a sequence CR / LF. 10 In binary mode, all characters are read in or displayed without translation.

Return value In case of successful execution, fopen returns a pointer to the FILE-structure assigned to the newly opened file; in case of error, the zero pointer ZERO is returned. Example FILE *fp, *wfile; fp = fopen("example.dat","r+"); wfile = fopen(tmpdat[i],"wb+"); 5.17.2.1 Particularity when indicating the file name in case of BORLAND-C

Attention If a path should be indicated in the filename filename, it must be considered, that the path separator \ should be indicated double. If the file is named

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
\user\dir\xyz.dat, then the following string must be indicated: \\user\\dir\\xyz.dat 5.17.3 freopen allocates new file to buffer Syntax #include <stdio.h> FILE *freopen( const char *filename, const char *mode, FILE *stream); Description Closes an already opened file, allocates its FILE-structure for a new file and opens this new file. freopen is mainly used to divert stdin, stdout or stderr to a file during the program flow.

Example /* The standard output is diverted to the "new.dat" file: */ fp = freopen("new.dat","w", stdout); 5.17.4 fclose closes a file Syntax #include <stdio.h> int fclose(FILE *stream); Description Because the number of opened files is limited and rest data can go lost in case of sudden interrupt (see "fflush empties the buffer" on page 134) files should be closed using the fclose-instruction, as soon as they are not used anymore. Bei normalem Programmende erfolgt ein automatisches Schlieen aller Dateien. Return value If the return value is 0, then the function was successful; if it is EOF, then it was not successful.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

Example ret = fclose(fp); 5.17.5 fflush empties the buffer Syntax #include <stdio.h> int fflush(FILE *stream); Description It writes the data buffer on the disk. (Only for files, which were opened for writing). The data buffer is usually written on the disk first, if it is full or if the file is closed. This function can be used for example in the following cases: If after a write command it must be avoided at any cost, that the data buffer goes lost through a faulty program end, then the data buffer must be ensured through the fflush-command. If the protocol file of a program should always contain the most up-to-date protocol status. That a use can read out for example the newest data while the program is still running, fflush must be called after each protocol entry. Return value If the return value equals 0, then the function was successful; if the return value is EOF, then it was not successful. Example ret = fflush(fp); 5.17.6 Character by character reading and writing Character by character reading and writing are implemented by one function each and an equivalent macro. The programmer should use either the macro or the function according to the following points of view: If a fast resolution is emphasized, then the macro should be used, because the overhead of a function call drops. If memory space is short, then the function should be used, because Then the entire implementation of the compiler is not filed at each call, instead of the call.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

5.17.6.1 Character by character reading Syntax #include <stdio.h> int fgetc(FILE *stream); /* Function */ or int getc(FILE *stream); /* Macro */ Description fgetc or getc read a character from the file, which is named by the FILE Pointer stream and delivers this character in the return value. Rckgabewert Im Fehlerfall oder wenn das Dateiende erreicht ist, wird als Rckgabewert EOF zurckgeliefert. Beispiel #include <stdio.h> void main(void) { char ch; printf("Enter a character:"); ch = getc(stdin); printf("The character was: '%c'\n", ch); } 5.17.6.2 Character by character writing Syntax #include <stdio.h> int fputc(int c, FILE *stream); /* Function */ or int putc(int c, FILE *stream); /* Macro */ Description fputc or putc write the character c in the file named by stream.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Return value In case of error, EOF is delivered as a return value. Example #include <stdio.h> void main(void) { char msg[] = "Hello world"; int i = 0; while (msg[i]) { fputc(msg[i], stdout); i++; } }

5.17.6.3 The macros getchar / putchar If inputs are read by stdin or outputs should be written on stdout, then the following macros could be used for simplification: #define getchar(void) getc(stdin) #define putchar(x) putc(x,stdout) Example /* The program reads a file character by character and displays these characters on standard display. The file name is transferred as a first argument at program call */ #include <stdio.h> void main(int argc, char *argv[]) { int character; FILE *fp; /* File (1. Argument) open for reading: */

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
if ((fp= fopen(argv[1], "r")) == NULL) { printf ("%s cannot be " "opened\n",argv[1]); exit(1); }

/* Display file until file end on standard output: */ while((character = getc(fp)) != EOF) putchar(character); } 5.17.6.4 Resetting characters Syntax #include <stdio.h> int ungetc(int c, FILE *stream); Description ungetc resets the character c back to the file characterized by stream. ungetc is not allowed to be called twice in a row. Thus only a character can be reset in a file. c is not allowed to be EOF! Return value The function delivers back c or EOF. Example /* In the 'GOODS' file there are product names and Article numbers filed in a sequence. The program fills the data in the structure field 'article' Example for the content of the 'GOODS' file: Butter786458763sausage78346567cheese765marmalade897...*/ ...

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
struct { char name[30]; char nr[20]; } article[100]; FILE *goods; int wi = 0; int nai;

/* Article name */ /* Article number */ /* Index in the article field */ /* Character index within an article name */ /* Character index within an article number */

int nri;

... goods = fopen("GOODS","r"); ... do { /* read article name: */ nai = 0; do { char = getc(goods); if (isalpha(char)) article[wi].name[nai++]= char; } while ((char != EOF) && isalpha(char)); if ((char!= EOF) && isdigit(char)) /* Reset digit: */ ungetc(char, goods); /* Read article number: */ nri = 0; do { char = getc(goods); if (isdigit(char)) article[wi].nr[nri++] = char; } while ((char != EOF) && isdigit(char));

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
if ((char != EOF) && isalpha(char)) /* Reset letter: */ ungetc(char, goods); wi++; } while (char != EOF); ... 5.17.7 Reading and writing strings 5.17.7.1 Reading strings Syntax #include <stdio.h> char *fgets(char *s, int n, FILE *stream); Description fgets reads from the file, which is characterized by stream, either one strings (string until \n inclusive) or until EOF or n-1 character after s. The string is finalized with \0. Return value In case of error or EOF the return value is ZERO; usually s is returned. Example #include <stdio.h> void main(void) { FILE *stream; char msg[20]; /* Open file for reading: */ stream = fopen("DUMMY.FIL", "r"); /* Read string from file:*/ fgets(msg, sizeof(msg), stream); /* Display string: */ printf("%s", msg);

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

fclose(stream); } 5.17.7.2 Write string Syntax #include <stdio.h> int fputs(const char *s, FILE *stream); Description: fputs writes the character string starting with s until \0 exclusively, in the file, which is characterized by stream. Return value: In case of error EOF is returned, otherwise a random, not-negative number value.

Example #include <stdio.h> void main(void) { /* Write a string on standard output: */ fputs("Hello world\n", stdout); } 5.17.8 Formatted reading and writing 5.17.8.1 Formatted reading Syntax #include <stdio.h> int fscanf(FILE * stream, const char *format[, address, ...]);

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Description fscanf reads from the stream file characters, modifies them according to the formats into format and stores them in the arguments at address etc. The format rules are the same as for scanf (see "Input with scanf" on page 45). Return value The number of successfully read-in elements EOF or 0 (error detection). 5.17.8.2 Formatted writing Syntax #include <stdio.h> int fprintf (FILE *stream, const char *format[, argument, ...]); Description fprintf writes into the stream file. Function like printf (see "Output with printf" on page 40) Example /* The program excerpt formats a file into another one. A sentence of the source file: Huber Friedrich 1.2.34 19389.98 667890 Donaustr.3 According sentence of target file: 667890 Friedrich Huber 01.02.1934 19389.98 */ ... FILE *source, *target; int sretc; /* Buffer for return value of "fscanf" */ source = fopen("source.dat", "r"); target = fopen("target.dat", "w+"); ... while ((sretc = fscanf(source, "%s %s %d.%d.%d %f %ld %s%d", name, first name, &day, &month, &year, &yincome, &persnr, street, &housenr.))

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
== 9 ) { fprintf(target, "%-10ld%-12s%-15s%02d.%02d.19%02d%10.2f\n", persnr, first name, name, day, month, year, jincome); } ... How must the variables be defined? char name[MAX_NAME]; char first name[MAX_FIRST_NAME]; char street[MAX_STREET]; int day, month, year; int house number; float jincome; long persnr;

5.17.9 Reading and writing block by block 5.17.9.1 Reading block by block Syntax #include <stdio.h> size_t fread(void *ptr, size_t size, size_t n, FILE *stream); Description fread reads n-times size bytes from the file characterized by stream, after ptr. Return value Number of actually read elements; if 0 is returned then an error or EOF has appeared. If the return value equals n, then all desired data could be read. Example anz = fread(buf,10,5,fp); /* Reads 5 units

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
for each 10 bytes "fp" after "buf" */ Example anz = fread ( buf,sizeof(buf),1,fp); /* Reads as many characters as there can fit into "buf" from "fp" tp "buf" */ 5.17.9.2 Writing block by block Syntax #include <stdio.h> size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream); Description fwrite writes n-times size bytes from ptr into the file, which is characterized by stream. Return value If the return value coincides with n, then the function was successful; in all other cases an error has occurred. Example #include <stdio.h> struct mystruct { int i; char ch; }; void main(void) { FILE *stream; struct mystruct s; stream = fopen("TEST.LST", "wb"); s.i = 0; s.ch = 'A'; fwrite(&s, sizeof(s),

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
1, stream); /* write structure "s" into the file */ fclose(stream); /* close file */ } 5.17.10 Functions for random file accessing The functions named up to now have been for sequential data access; this means that after opening, a file was continuously read / written from the start to the end. To create more complex files, the help functions described in the following are available for random access. 5.17.10.1 fseek Positioning of the write / read pointer Syntax #include <stdio.h> int fseek(FILE *stream, long offset, int whence); Description fseek shifts the read / write pointer of the stream file by the number of bytes indicated in offset. Thus an offset higher than 0 means a shifting to the file end and smaller than 0 a shifting to the file start. The parameter whence indicates from which reference point the shifting should be made; the corresponding constants are defined in stdio.h: Constant SEEK_SET SEEK_CUR SEEK_END Return value fseek returns 0, if the write / read pointer could be shifted successfully and another random value, if an error has occurred. Example Numeric value 0 1 2 Meaning Shifting from file start Shifting from current position Shifting from file end

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
/* The program reads from "file_1" starting with the n block z blocks and writes them in "file_2". Command lines arguments: file_l: 1. argument file_2: 2. argument n: 3. argument z: 4. argument A block should consist of 5 characters. No error handlings occur. */ #include <stdio.h> #define B_SIZE 5 void main(int argc, char *argv[]) { FILE *fp1, *fp2; char buf[B_SIZE]; int i, b_number;

fp1 = fopen(argv[1],"r"); fp2 = fopen(argv[2],"w"); fseek(fp1,(atol(argv[3])-1) * B_SIZE, 0); b_number = atoi(argv[4]); for (i = 0; i< b_number; i++) { fread(buf, B_SIZE, 1, fp1); fwrite(buf, B_SIZE, 1, fp2) ; } } 5.17.10.2 ftell Indicating the position of the write / read pointer Syntax #include <stdio.h> long int ftell(FILE *stream);

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Description ftell delivers the number of bytes, by which the read / write pointer is distanced from the stream file start. 5.17.10.3 rewind Resetting the write / read pointer Syntax #include <stdio.h> void rewind(FILE *stream); Description rewind sets the read / write pointer of a file stream on the file start and thus deletes the EOF-characteristic and the error detection.

5.17.11 feof Detecting the file end Syntax #include <stdio.h> int feof(FILE *stream); Description feof checks, whether the file end was reached through a previous reading of the file end. Return value Returns 0, if the file end was not yet reached, otherwise a value unequal 0. Successful test What does the following program display? #include <stdio.h> #define STRING_SIZE 34

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
void main(void) { FILE *fp; int zz = 1; int i_var = 2; char c_var = 'A'; int i; char buf[100]; fp = fopen("example","w"); for (i = 0; i < 10; i++) { fprintf(fp,"string: %2d i_var: %2d " "c_var: %c\n", zz++, i_var, c_var); i_var += 2; c_var++; }

fclose(fp); fp = fopen("example", "r"); fseek(fp,-((long) STRING_SIZE * 3), 2); while(fgets(buf,100, fp) != ZERO) printf("%s",buf); } Solution: String: 8 i_var: 16 c_var: H String: 9 i_var: 18 c_var: I String: 10 i_var: 20 c_var: J 5.18 Optimized organisation of same type structures Until now, same type structures, which should be managed and handled together in a program, are always applied in structure fields. This method is not always the best one (see "Definition of a structure field" on page 125). In this paragraph we get acquainted with alternative organisation types for same type structures, which do not present the disadvantages of structure fields.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Thus it is the case of Linked lists (see "Linked lists" on page 150) Binary trees (see "Binary trees" on page 163) Further on, the access to such organized structures can be accelerated by using hashing (see page 163). Linked lists and binary trees operate with recursive structures, which are discussed in the following paragraph. 5.18.1 Note for examples when using BORLAND-C 3.1 Due to a problem with the linker in BORLAND-C 3.1, the following two strings must be added at the beginning of each example porgram of this chapter: extern void _floatconvert(); #pragma extref _floatconvert 5.18.2 Definition of a recursive structure We can talk about a recursive structure, if the pointer structure contains structures of the same structure type. Example struct management { struct management *back_poi; struct management *front_poi; char dat_name[l4]; } disk_management; 5.18.3 Linked lists A linked list is an organisation of same type structures, where the individual structures contain at least one pointer, which indicates to the next structure within a desired sorting of individual structures. The memory space for each structure within this linked list is allocated individually. Thus the following features result: Advantages of linked lists The memory space necessity for the structures can be adapted exactly to the actual needs during runtime. Introduction and removal of individual structures while keeping a sorting of structures is possible without re-copying of structures.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Disadvantages of linked lists Access to individual structures is possible only sequential and thus slower. 5.18.3.1 Simple forward linked list The simple forward linked list is characterized by the following: There is a pointer, which is designated as an anchor, which indicates to the first element of the list. This element was first read in when the list was made. If the list is empty, then the anchor points to ZERO. Each list element contains a pointer, which indicates to the next element of the list. The last element then contains a pointer, which shows ZERO, thus to indicate the end of the list. A simple forward linked list is especially suitable for lists, where the access structure to the list elements should occur in the same sequence as the structure. Example #include <stdio.h> #include <stdlib.h> /* Structure declaration: */ typedef struct person { char name[30]; int age; float c_note; struct person *next; }schueler; /* Global pointer on structure for the anchor of linked list: */ student *anchor=ZERO; /* Function declarations: */ void linkstruct(void); /* builds from a file a simply linked list */ void list(void); /* displays the simple linked list */ void main(void)

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
{ linkstruct(); /* Function call Build string */ list(); /* Linked list display */ }

/* Open a fixed preset file for reading and read out Data set by data set in structures; the structures should be linked to a simple linked, where the first read in data set becomes the start of the linked list */ void linkstruct(void) { FILE * fp; student *hp1, *hp2; if ((fp = fopen("student.dat", "r")) == ZERO) { printf("File cannot be opened" "for reading\n"); exit(-1); } while (!feof(fp)) { if ((hp1 = (student *) malloc(sizeof(student))) == ZERO) { printf("Not enough memory" "available\n"); exit(-2); } if (3 == fscanf(fp, "%s %d %f", hp1->name, &hp1->age, &hp1->c_note)) { /* Link, so that the element which was read in first is the anchor of the linked list: */ if (anchor == ZERO) { /* It is the first element which should be

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
read in; this is why an anchor must be set */ anchor = hp1; } else { /* It is not the first element; so set the next-pointer of the previous one to the current data set */ hp2->next = hp1; } hp1->next = ZERO; hp2 = hp1; } } fclose(fp); } /* Output of simple linked list: */ void list(void) { student *hp; for (hp = anchor; hp != ZERO; hp = hp->next) printf("Name: %s Age: %2d C-Note: %.2f\n", hp->name, hp->age, hp->c_note); } 5.18.3.2 Simple backwards linked list The simple, backwards linked list is characterized by the following: There is a pointer, which is marked as an anchor, which indicates to the last element of the list. This element was read in last when the list was structured. If the list is empty, then the anchor points to ZERO. Each list element contains a pointer, which indicates to the previous element of the list. The first element then contains a pointer, which indicates ZERO, thus to mark the beginning of the list.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
A simple backwards linked list is especially suitable for lists, for which the structure of access to the list elements may also occur in a backward structure sequence for this type of linked list, the structure is very simple. Example #include <stdio.h> #include <stdlib.h> /* Structure declaration: */ typedef struct person { char name[30]; int alter; float c_mark; struct person *prev; }student; /* Global pointer on structure for the anchor of the linked list: */ student *anchor = ZERO; /* Function declarations: */ void linkstruct(void); /* makes a simple linked list from a file */ void list(void); /* displays the simple linked list */ void main(void) { linkstruct(); /* Function call Build link */ list(); /* Display linked list */ }

/* Open a fixed preset file for reading and read out data set for data set in structures; Link the structures to a simple linked list, where the last read in data set becomes the end of the linked list */ void linkstruct(void) { FILE * fp;

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
student *hp; if ((fp = fopen("student.dat", "r")) == ZERO) { printf("File cannot be opened for " "reading\n"); exit(-1); } while (!feof(fp)) { if ((hp = (student *) malloc(sizeof(student))) == ZERO) { printf("Not enough memory" "available\n"); exit(-2); } if (3 == fscanf(fp, "%s %d %f", hp->name, &hp->age, &hp->c_mark)) { /* Link so that the element which was the last one read in becomes the anchor of the linked list */ hp->prev = anchor; anchor = hp; } } fclose(fp); } /* Output of the simple linked list: */ void liste(void) { student *hp; for (hp = anchor; hp != ZERO; hp = hp->prev) printf("Name: %s Age: %2d C-Mark: %.2f\n", hp->name, hp->age, hp->c_mark); } 5.18.3.3 Double linked list

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
A double linked list is characterized by the following: There is a pointer, which is named anchor, and it points to the first element of the list. This element was first read in when the list was built. If the list is empty, then the anchor points to ZERO. Each list element contains a next-pointer, which indicates the next element of the list and a further prev-pointer, which indicates the previous list element. The last element then contains a next-pointer, which indicates to ZERO, to mark the end of the list; the same way, the first element contains a prev-pointer, which points to ZERO, thus to mark the beginning of the list. A double linked list is especially suitable for lists, which are to be ran through forwards and backwards rather easily; in addition, the insertion of list elements while keeping an already existing sorting or even deletion of list elements is somewhat easier than in case of simple linked lists. Example #include <stdio.h> #include <stdlib.h> /* Structure declaration: */

typedef struct person { char name[30]; int age; float c_mark; struct person *next; /* Pointer on next element */ struct person *prev; /* Pointer on previous element */ } student; /* Global pointer on structure for the header of the linked list: */ student *anchor = ZERO; /* Function declarations: */ void linkstruct(void); /* builds from a file a double linked list */ void list(void); /* displays the double linked list */

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
void main(void) { linkstruct(); /* Build Link function structure */ list(); /* Display linked list */ } /* Open a fixed preset file for reading and read out data set by data set in structures; Connect structures to a double linked list: */ void linkstruct(void) {

FILE * fp; student *hp, *hp2; if ((fp = fopen("student.dat", "r")) == ZERO) { printf("File cannot be opened " "for reading\n"); exit(-1); } while (!feof(fp)) { if ((hp = (student *) malloc(sizeof(student))) == ZERO) { printf("Not enough memory" "available\n"); exit(-2); } if (3 == fscanf(fp, "%s %d %f", hp->name, &hp->age, &hp->c_mark)) { if (anchor == ZERO) { /* The first element should be read in: */ hp->prev = ZERO; hp->next = ZERO;

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
anchor = hp; } else { /* The read-in element is not the first element, attach new element: */

hp2->next = hp; hp->prev = hp2; hp->next = ZERO; } hp2 = hp; /* memorize address of old element in hp2 */ } } fclose(fp); } /* Output of double linked list: */ void list(void) { Student *hp; for (hp = anchor; hp != ZERO; hp = hp->next) printf("Name: %s Age: %2d C-Mark: %.2f\n", hp->name, hp->age, hp->c_mark); } 5.18.3.4 Ring link In case of ring links there are also simple and double linked variants, but only the double linked variant is described here. A list with ring links is characterized by the following:

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

There is a pseudo-element of the list, which is marked as an anchor. This structure contains no important information whatsoever, except for the nextpointer, which indicates the next element in the list, and the prev-pointer, which indicates the previous element in the list. If the list is empty, then the anchor still exists, but the next-pointer as well as the prev-pointer show in this case the anchor itself. Each list element contains a next-pointer, which indicates the next element of the list and another prev-pointer, which indicates to the previous list element. The last element then contains a next-pointer, which points out to the anchor, thus to show the end of the list; the same way, the first element contains a prevpointer, which indicates the anchor, thus to mark the beginning of the list. A list with ring links is characterized by the fact that no difference has to be made between "empty list", "first element", "other elements" or "last element" when inserting or deleting elements; thus the program works faster than with other list types. Example #include <stdio.h> #include <stdlib.h> /* Structure declaration: */ typedef struct person { char name[30]; int age; float c_mark; struct person *next; /* Pointer on next element */ struct person *prev; /* Pointer on previous element */ }student; /* Anchor is a pseudo-element, which contains no important information and only containt the pointer "next" for the first and "prev" for the last element: */ student anchor= { "", /*No name */ 0,0.0, /*Age and C_mark make also no difference */ &anchor, &anchor /* is its own precursor and successor

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
*/ }; /* Function declarations: */ void ringauf(void); /* builds from a file a ring-like linked list */ void list(void); /* displays the ring/like linked list */ void main(void) { ringstruct(); /* Call of ring build function */ list(); /* Ring display */ } /* Open a fixed preset file for reading and read out data set by data set in structures; link the structures to a ring-like linked list: */ void ringstruct(void) { FILE * fp; student *ptr, *hp; ptr = &anker; if ((fp = fopen("student.dat", "r")) == ZERO) { printf("File cannot be opened" "for reading\n"); exit(-1); } while (!feof(fp)) { if ((hp = (student *) malloc(sizeof(student))) == ZERO) { printf("Not enough memory " "available\n"); exit(-2); }

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
if (3 == fscanf(fp, "%s %d %f", hp->name, &hp->age, &hp->c_mark)) { /* Precursor of current sentence becomes the Precursor of the new sentence: */ hp->prev = ptr->prev; /* Current sentence becomes the successor of the new sentence: */ hp->next = ptr; /* New sentence becomes the successor of the old predecessor: */ (ptr->prev)->next = hp; /* New sentence becomes precursor of the current sentence: */ ptr->prev = hp; /* New sentence becomes current sentence: */ ptr = hp; } } fclose(fp); } /* Ring output: */ void list(void)

{ student *hp; /* Set pointer on the first correct element and Display, for as long as the dummy element is reached again: */ for (hp = anchor.next; hp != &anchor; hp = hp->next) printf("Name: %s Age: %2d C-Mark: %.2f\n", hp->name, hp->age, hp->c_mark); }

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
5.18.4 Binary trees A binary tree is an organisation of same type structures, where the individual structures are marked as "knots". These knots contain Two pointers, which indicate to a "branch" each (marked as "left branch" and "right branch"). Each branch consists of a knot with the attached branches; if one of the branches does not exist, then this is marked by the fact, that the pointer of the knot, where this branch is linked is set to ZERO. As opposed to a linked list, in case of a binary tree it is not a linear but an areal formation. The tree is basically structured in such way, that structures are sorted according to one or several criteria. According to this sorting if they are "smaller" than the respective knot they are attachet to the "left" branch, and the other in the "right" branch. The memory space for each structure within this binary tree is allocated individually. The best way to realize functions for handling a binary tree (building the tree, searching the tree according to a certain structure, content display of the entire tree etc.) is by using recursive functions (see "Recursive function call" on page 107). The following features result: Advantages of binary trees The memory space necessity for the structures can be adapted right to the actual needs during runtime. Through the areal structure, search processes can run very fast, because the search does not occur linearly anymore (as in linked lists), searching through all elements.

Disadvantages of binary trees The structure of a binary tree is somewhat complicated. When building the tree, branches of different length can result according to the incidental occurence of the structures to be implemented in the tree. They can partly decrease the speed advantages again. There are however algorithms, which make sure the trees are balanced (for example AVL-trees). Example

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
#include <stdio.h> #include <stdlib.h> /* Structure declaration for binary tree: */ typedef struct person { char name[30]; int age; float c_mark; struct person *left; /* Pointer on left subtree */ struct person *right; /* Pointer on right subtree */ } t_student; /* Function declarations: */ /* Searches the correct installation location and introduces The data set: */ t_student * treestruct(t_student *knot, t_student *sentence); /* displays the binary tree: */ void t_list(t_student *knot); void main(void) { t_student *root = ZERO;/* Shows nothing in the beginnig */ t_student *ptr; FILE *fp; /* Open file for reading: */ if ((fp = fopen("student.dat", "r")) == ZERO) { printf("File cannot be opened " "for reading\n"); exit(-1); } /* read up to file end: */ while (!feof(fp)) { /* Get memory for data set: */ if ((ptr = (t_student *) malloc( sizeof(t_student))) == ZERO) { printf("Not enough memory " "available\n");

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
exit(-2); } /* Read in data sets: */ if (3 == fscanf(fp, "%s %d %f", ptr->name, &ptr->age, &ptr->c_mark)) { ptr->left = ZERO; ptr->right = ZERO; root = treestruct( root,ptr); /* Function call, to find the right installation location */ } else /* no entire data set; release unnecessary Memory space: */ free(ptr);

} t_list(root); /* display binary tree */ } /* Find installation location and link in new data set: */ t_student * treestruct (t_student *knot, t_student* sentence) { /*Found correct installation location:*/ if (knot == ZERO) knot = sentence; else { /* search correct installation location: */ /* Query 1. criteria (C_grade): */ if (knot->c_mark < sentence->c_mark) knot->right = treestructu(

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
knot->right, sentence); else if (knot->c_mark > sentence->c_mark) knot->links = treestruct( knot->left, sentence); else { /* C-grades are not equal: 2. Sorting criteria is age */ if (knot->age < sentence->age) knot->right = treestruct( knot->right, sentence); else knoten->left = treestruct(knot>left, sentence); } } return knot; } /* Output of binary tree */ void t_list(t_student * knot) { /* Only to be displayed, if the knot is not empty: */ if (knot != ZERO) { /* First display the left: */ t_list(knot->left); /* Then display itself: */ printf("Name: %s, Mark: %.2f, Age: %d\n", knot->name, knot->c_mark, knot->age); /* Finally display the correct branch: */ t_list(knot->right); } } 5.18.5 Hashing Hashing is a method to increase access to linked lists or binary trees.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
The main idea is the division of linked lists or binary trees into several linked lists or binary trees, whose anchors are addressed over the so-called hash table of the preset size (HASHSIZE). In extreme case, these lists or trees can show degenerated types with only one structure element. The acceleration consists now of the fact, that only a part of the list or tree must be searched by using hashing. The classification of structures into different lists or trees happens based upon the hash index, which serves as an index for the hash table. This index is calculated from one or less arbitrary algorithm from the contents of the structures. If the same hash index is calculated for two different structures based upon this algorithm, then we can say this is a hash collision. A good hash algorithm should be made in such way, that the accumulated structures are set in part lists or trees as balanced as possible. The hash method described here is named "Separate Chaining". Apart from this, there is also the so-called "Open addressing", where the hash table contains no pointer on part lists or part trees, but pointers to the structures themselves; if a hash collision appears when building a table, then the entry is set in the next free cell of the table. When searching, this often leads to superfluous searches, which partly cancels the hashing advantage; this is why this technique is not further explained here. Example /* Build a hash table from the student data, table which points out to several linked lists. Finally the user is asked to enter a name and the corresponding data set is searched and displayed through the hash table */ /* Format used in the file: <name> <age> <c_mark> Bsp.: Meier 47 2.8 */ /* File name with student data: */ #define IN_FILE "studentdat" #include <stdio.h> #include <malloc.h> #include <process.h> #include <string.h> /* ----------------------------------------------*/ /* Definitions and declarations for linked list: */

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

typedef struct student { char name[50]; int age; float c_mark; struct student *next; } s_data; #define HASHSIZE 10 s_data *hashtable[HASHSIZE]; /* Hashtable, all pointers show at the beginning to ZERO */ /* ----------------------------------------------*/ /* Hash function (is needed for building and read out !) */ /* The hash function selected here: adds all letters in a name. This hash function is only suitable, if the name is taken as search criteria. */ int hashfunc (char *namen) /* Returns the value of the Hashindex back for the preset name */ { int value = 0; /* Buffer for the sum of letters */ int index; /* Run index for passing through the string */ for (index = 0; index < strlen(names); index++) value += names[index]; return (value % HASHSIZE); } /* -----------------------------------------------*/ static void linkstruct(void) {

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

s_data *s_poi; FILE *infile; int hashindex;

/* Start address for a new structure */ /* Input file */ /* Hashindex of the already handled record */

/* Open input file: */ if (ZERO == (infile = fopen(IN_FILE,"rt"))) { printf("Cannot open data file %s \n", IN_FILE); exit(1); } /* Read in file: */ do { /* Allocate memory: */ if ((s_poi = (sdata *) malloc( sizeof (s_data))) == ZERO) { printf("Memory full\n"); exit(2); } /* Read from file: */ if (3 != fscanf(infile,"%s%d%f",s_poi->name, &(s_poi->age), &(s_poi->c_mark))) break; /* Exit, if nothing readable from the file anymore */ /* Calculate hash index for this record: */ hashindex = hashfunc(s_poi->name); /* Record is simply sorted by the already existing one */

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
/* the first in the list is the successor of the current one: */ s_poi->next = hashtable[hashindex]; /* current one becomes the first: */ hashtable[hashindex] = s_poi; } while (!feof(infile)); } /* -----------------------------------------------*/ void such(char *names) /* Searches for a name in the database and returns all "hits": */ { int hashindex; s_data *ptr; /* Calculate hashindex for given names: */ hashindex = hashfunc(names); /* Search this name in corresponding list: */ for (ptr = hashtable[hashindex]; ptr != ZERO; ptr = ptr-> next) { if (strcmp(name, ptr->name) == 0) /* Found ? */ printf("%s %d %3.1f\n", ptr->name, ptr->age, ptr->c_mark); /* Yes, display */ } } /* -----------------------------------------------*/

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
void main(void) { char buffer[200]=" "; /* Who enters a longer one ... */ Linkstruct(); /* Structure of linked list from a file */ while (strcmp( buffer,"exit") != 0) /* As long as "exit" is found in the buffer continue */ { printf("Please enter name (for " "Ending enter \"exit\"): "); scanf("%s",buffer); /* Read in names */ /* Search names and display if necessary: */ search(buffer); } } 5.19 Bit fields In C there is the possibility to display information as individual bits of the bit groups. This is necessary if: Memory space must be saved, Data structures with a lot of information content must be managed (where the elements do not need the numeric range of the basic data types), Interfaces to peripheral devices must be operated.

Example This example is a Bitfield, which contains the status bits of a printer: struct { unsigned ready :1; unsigned blocked:1; unsigned :3; /* unused */ unsigned lines :6; unsigned paper :1; } dr_status;

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
The definition of a Bit field is made with the keyword struct. The individual elements of the bit field must be declared unsigned. The bit width of an element is indicated behind the element name, separated by a colon. Unallocated bit fields are presented without a name. As in structures, the type of a bitfield can be declared. Fields can be defined by bitfields. The definition of pointers on bit fields is possible. Bit fields are justified to word limits (this means 16 Bits). The lowest value Bit is first described and the highest value bit the last, this means in ascending order. The elements of a bit field are accessed like structure elements. Example dr_status.ready = TRUE; if (dr_status.line > 30) ... Often a bit access is made not with bit fields but with bit masks. 5.20 Bit masks Example #define INIT 0x07 #define READY 0x08 #define WAIT 0x10 unsigned int status = 0; ... status |= INIT | WAIT; /* Setting the bits */ ... status &= ((INIT | WAIT)); /* Deleting the bits */ ... if (( status & READY) == 0) /* Query of a bit */ ... 5.21 Unions (Variants) With a union, elements of different data types can be displayed on the same memory space, at different times. A union allocates as much memory space as the largest element needs.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
For the definition, declaration, access and pointer, the same rules are applied as for structures (see "Simple structures" on page 122). Instead of the control word Struct, union will be used. Example A function should be able to process parameters of different data types. The function should do the following: If the first two parameters are of the type int or float, then it should add the values addressed through the pointer and store the result at the address of the first parameter. In case of char-pointers, the second string should be attached to the first string. The type of the address parameter should be characterized by the 3rd parameter. Declaration of the union-type par_typ: union par_type { int *i_type; float *f_type; char *c_type; };

Function definition void func (union par_typ p1, union par_typ p2, char p_typ) { switch (p_typ) { case 'i': *(p1.i_typ) += *(p2.i_typ); break; case 'f': *(p1.f_typ) += *(p2.f_typ); break: case 'c': strcat(p1.c_typ, p2.c_typ); break; default: printf("Parameter error \n"); break; } }

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

Example Declaration of the union type all_typ union all_type { int i_type; float f_type; char c_type; }; Definition of a structure field symtab (Symbol table) struct { char symname[20]; char u_type; union all_type sym_value; } sym_tab[SYM_SIZE];

Access to an element switch(sym_tab[i].u_type) { case 'i': printf("%20s %10d \n", sym_tab[i].sym_name, sym_tab[i].sym_value.i_type); break; case 'f': printf("%20s %10f \n", sym_tab[i].sym_name, sym_tab[i].sym_value.f_type); break; case 'c': printf("%20s %10c \n", sym_tab[i].sym_name, sym_tab[i].sym_value.c_type);

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
break;

6 Some C-library functions 6.1 String processing String functions assume that a string is a character sequence, which is ended by \0. 6.1.1 strcat Syntax #include <string.h> char *strcat(char *dest, const char *src);

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Description strcat appends a copy of the src string to the end of the dest string. The length of the resulting string is strlen(dest) + strlen(src). Return value strcat returns a pointer on both strings which are linked together. 6.1.2 strncat Syntax #include <string.h> char *strncat(char *dest, const char *src, size_t maxlen); Description strncat copies at most maxlen characters of the src string at the end of the dest string and then attaches a string end character (\0). The maximum length of the resulting string is strlen(dest) + maxlen. Return value strncat returns dest.

6.1.3 strchr Syntax #include <string.h> char *strchr(const char *s, int c); Description strchr searches a string s in forward direction after the first occurrence of a preset character c. The binary zero finishing in the string is thus seen as a being part of the string; for example strchr(strs,0)returns a pointer to the finishing zero of the strs string.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

Return value strchr returns a pointer upon the first occurrence of the character c in the string s ; If c does not appear, then strchr returns ZERO. 6.1.4 strcmp Syntax #include <string.h> int strcmp(const char *s1, const char *s2); Description strcmp performs an unsigned comparison of s1 with s2, while it starts with the first character in each string and continues with each next character, as far as the corresponding characters do not differ from each other or the end of one of the strings is not yet reached. Return value If s1 is... Smaller than s2 Equal s2 Higher than s2 6.1.5 strncmp Syntax #include <string.h> int strncmp(const char *s1, const char *s2, size_t maxlen); Description strncmp makes the same unsigned comparison as strcmp, but does not regard as maxlen character anymore. strncmp starts with the first two characters in each string and continues with the following character until either different characters were detected or maxlen characters were compared. Return value ...then strcmp returns a value: < 0 == 0 >0

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
If s1 is... Smaller than s2 Equal s2 Higher than s2 6.1.6 strcpy Syntax #include <string.h> char *strcpy(char *dest, const char *src); Description strcpy copies src on dest and stops as soon as the string src final binary zero was copied. Return value strcpy returns dest. 6.1.7 strncpy Syntax #include <stdio.h> char *strncpy(char *dest, const char *src, size_t maxlen); Description strncpy copies until maxlen characters from src to dest, where dest is either cut off or finalized with a binary zero. The target string dest is not finalized with a binary zero, if the string length of src is equal or higher than maxlen. Return value strncpy returns dest. 6.1.8 strlen ...then strncmp returns a value: < 0 == 0 >0

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Syntax #include <string.h> size_t strlen(const char *s); Description strlen calculates the length of the s string. Return value strlen returns the number of characters in s without the zero which finishes the string. 6.1.9 strtok Syntax #include <string.h> char *strtok(char *s1, const char *s2);

Description strtok understands the s1 string as a sequence of no or several keywords (tokens), which are separated by one or several separators of a separator string s2. The first call of strtok returns a pointer to the first character of the first token in s1 and writes a binary zero after s1 immediately after the first token. Further calls of strtok with ZERO as the first parameter work themselves up through the entire s1 string in this way, until there are no more tokens. The separator string can be otherwise defined at each of these calls, according to the needs. Return value

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
strtok returns a pointer on the found token in s1. ZERO is returned, if no further tokens are available. Example #include <string.h> #include <stdio.h> void main(void) { char input[16] = "abc,d"; char *p; p = strtok(input, ","); if (p != ZERO) printf("%s\n", p); p = strtok(ZERO, ","); if (p != ZERO) printf("%s\n", p); }

6.2 Converting character strings to numbers 6.2.1 atoi Syntax #include <stdlib.h> int atoi(const char *s); Description

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
atoi transforms a string s into an integer value, thus atoi detects in the following sequence: an optional string of tab characters and blanks ein optional prefix a string of numbers The first unrecognized character ends the conversion for this function. There are no provisions against overflow; in such case the results are undefined. Return value atoi returns the converted numeric value. If the string cannot be coverted into a number of the desired type (int), then atoi returns 0. 6.2.2 atol Syntax #include <stdlib.h> long atol(const char *s); Description atol converts a string s into a long value, thus atol detects in the following sequence: an optional string of tab characters and blanks an optional prefix a digit string

The first unrecognized characters end the conversion for this function. There are no provisions agains overflow; in such case the results are undefined. Return value atol returns the converted numerical value back. If the string cannot be converted in a number of the desired type (thus long), then atol returns 0.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
6.2.3 atof Syntax #include <math.h> double atof(const char *s); Description atof converts a string s into a double-value; this function detects a text representation of a floating point number, which is made of the following elements: an optional string of tab characters and blanks an optional prefix a string of digits and an optional decimal point, where the numbers can be distributed before or/and after the decimal point an optional letter e or E, where an optional prefix signed integer number can be appended. The first undetected character ends the conversion for this function. Return value atof returns the transformed numeric value back from the s string. 6.2.4 sscanf Syntax #include <stdio.h> int sscanf(const char *buffer, const char *format[, address, ...]);

Description This function works the same way as scanf (see "Input with scanf" on page 45) with the difference, that it does not read from a stream, but from the buffer field. Return value

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
In case of success, sscanf returns the number of successfully read-in, converted and stored input fields; this counting does not include the read in, but not stored input fields. If sscanf tries to read at the end of a string (thus the binary zero which ends the string), then EOF is returned. In case of error (if no fields were stored) then 0 is returned. 6.3 Macros for verifying character features Syntax #include <ctype.h> int <macro>(int c);

Description The macros serve for verifying the character features. Name of macro Meaning: character Numeric range is... isalnum Letter or digit ('A' <= c <= ('a' <= c <= ('0' <= c <= isalpha Letter ('A' <= c <=

'Z') or 'z') or '9') 'Z') or

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
('a' <= c <= 'z') 0 <= c <= 127 (c == 127) or (0 <= c <= 31) ('0' <= c <= '9') Printable character without blank ('a' <= c <= 'z') Printable character with blank Printable character except for blank, numbers and letters (9 <= c <= 13) or (32 == c) ('A' <= c <= 'Z') ('A' <= c <= 'F') or ('a' <= c <= 'f') or ('0' <= c <= '9')

isascii iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit

ASCII-character Control character Digit Visible character Small letter Printable character Punctuation mark Empty characters of all type Capital letters Hex number

Return value These macros return TRUE (thus a numeric value different of 0), if c is found within the preset numeric range, otherwise FALSE (0). 6.4 Macros for character conversion 6.4.1 tolower Syntax #include <ctype.h>

int tolower(int ch); Description tolower converts a capital letter (A...Z) ch into a small letter (a...z). All other characters remain unchanged.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
Return value tolower returns the converted value of ch as small letter, as far as ch is a capital letter; otherwise tolower returns ch. 6.4.2 toupper Syntax #include <ctype.h> int toupper(int ch); Description toupper converts a small letter (a...z) ch into a capital letter (A...Z). All other characters remain unchanged. Return value toupper returns the converted value of ch as a capital letter, as far as ch has a small letter; otherwise toupper returns ch. 6.5 Random numbers generator Using the rand function, pseudo-random numbers can be taken from a random number generator, which can be initialized with the srand function. 6.5.1 rand Syntax #include <stdlib.h> int rand(void);

Description rand uses a random number generator with an extent of 232 for generating Pseudo-random numbers in the range between 0 and RAND_MAX. The constant RAND_MAX is defined in stdlib.h. Return value rand returns the generated pseudo random number.

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________

Example #include <stdlib.h> #include <stdio.h> void main(void) { int i; printf("10 random numbers from 0 to 99\n\n"); for(i=0; i<10; i++) printf("%d\n", rand() % 100); } 6.5.2 srand Syntax #include <stdlib.h> void srand(unsigned seed); Description The random number generator is only started, by calling srand with seed = 1. The random number generator can be set on another start value, by selecting another value for seed. Same seed-values guarantee identical sequences of random numbers. Return value None.

Example /* In this example the time in seconds is simply used as a parameter for 'srand'; this way other random numbers are generated at each program call */ #include <stdlib.h> #include <stdio.h> #include <time.h>

_______________________________________________________ Version IT2.0

Ruth Schubert

C-Course

20.03.99

_______________________________________________________
void main(void) { int i; time_t t; srand((unsigned) time(&t)); printf("10 Random numbers from 0 to 99\n\n"); for(i=0; i<10; i++) printf("%d\n", rand() % 100); } 6.6 Program ending Syntax #include <stdlib.h> void exit(int status); Description exit ends the running program. Before program end, all open files are closed and buffered outputs which wait for output are written. status is provided to return an error status to the operating system, from which the program was started. Usually, zero means an error free program end and all other values some type of error. Return value None.

_______________________________________________________ Version IT2.0

Вам также может понравиться