Overview of programming in C
description
Transcript of Overview of programming in C
Overview of programming in C
• C is a fast, efficient, flexible programming language
• Paradigm: C is procedural (like Fortran, Pascal), not object oriented (like C++, Java)
• C code is compiled, not interpreted (like python, perl, java) higher speed
• High degree of memory control (pointers, dynamic allocation), compiled code much faster than mathematica et al.
• Very efficient compilers available, very fast and portable
• Similar syntax to Java
• Together with Fortran most commonly used platform for HPC
• All of Unix is written in C!
Basic programming cycle
• Write your program in a text editor (for example emacs)
/* hello world */#include <stdio.h>int main() { printf("Hello world.\n"); return 0;}
• Compile: invoke gcc -o hello hello.c on the command line• Run: type hello• Analyse output (gnuplot, etc)
• Note: name of compiler may vary: gcc (GNU), icc (intel), cc (Sun), pgcc (portland group)
Structure
• Comments appear in /* */ or start with // for one line comment
• Each line ends with ;
• A C program consists entirely of functions
• It must have at least one special function:int main () { variable declarations … function1(); function2(); …}
which can call additional functions to perform operations• Functions other than main() must be first declared, then defined:
Ex: int function1();
Functions
• Example:
int multbytwo(int x) { int retval; retval = x * 2; return retval; }
• You can declare a prototype int multbytwo(int);
before main() and define the function later
• Functions of type int or double require a return statement;void returns nothing
A typical program• /* include statements */
#include <stdio.h> // basic io-capability#include <math.h> // basic math: exp,sin,cos,… /* function declarations */void initialize(); // read in parameters for simulationvoid compute(int); // perform actual computation void output(); // produce output, write data to file int main() {initialize();compute(int);output();}
/* function definitions */void initialize(){…}
• In longer programs, function declarations are moved to "header" (.h) files
Data types• int: integer (4 bytes on 32-bit machines encodes 232 numbers)
Ex: int n=100;• float: real number (4 bytes)
Ex: float x=0.4502;• double: high (double) precision real number (8 bytes)• char: alphanumerical character (1/2 bytes)• The sizeof() command returns the # of bytes reserved for variable
Qualifiers:• const: will not change • long: increase storage (eg long int 64 bit)
Note:in C, all variables must be declared in the beginning before any non-declaratory statement; cannot use keywords!
Assignments and arithmetics
• Variables must be declared at start of function, same type can be grouped together, can be initialized at declaration:int l,m;m=5;l=10;l=m+l;
• double x=5.8,y,z;y=4.6;z=x*x+y*y;z=sin(x);
• Casting: change type of variablel=(int)z;
z=(double)m/(double)l; //ensures floating point division
Arithmetic operators• Assignment: =• Binary arithmetic: +, -, *, / , %
Can be applied to int, float or double except the modulus operator % (int only)
• Shortcuts: +=, -=, *=, /=x+=2; // equivalent to x = x+2; x*=2; // equivalent to x = x*2;
• Increment/Decrement: ++,--x++; // acts like x = x+1;x--; // acts like x = x-1;
• Both x++ and ++x are expressions, but ++x acts like x+1; Example: b=10; c=b++; // c is 10 and b is 11;b=10; c=++b; // c and b are now 11;
Output to screen: printf()
• Output to screen: printf("format string", var1, var2, var3);• Format string can be text or % for variables, followed by type
%d: integer %ld: long integer %f: float %c: character %s: stringmore general: %length.precision type, eg. %10.8f prints 10 total digits, 8 after the . point\n: newline (cr) \t: tab
• Example:
int x = 3;int y = 15;char op = '+';printf("\t%d %c %d = %d\n", x, op, y, x + y);
Result: 3 + 5 = 18;
• Note: input from screen: scanf() (later)
Scope of variables
• If declared within a function, the variables are only known to that function (local variable), i.e. within the {}
• If declared before main(), the variable is known to all functions and can be manipulated everywhere (global variable)
int i,j;// global variablesint main{ double x; // local variable}
• Global variables can be used to share information between functions, but this is not recommended/good style
• Better: variable pass by value or by pointer in function argument (later)
Flow control
• Branching with if … else#include <stdio.h> int main() { int cows = 6; if (cows > 1) printf("We have cows\n"); if (cows > 10) printf("loads of them!\n");}
• Format: if (expression) {statement;}else if (expression) {statement;}else {statement;}
• Useful operators in logical expression: relational: <, >, <=,>=,equality: ==, inequality: !=logical: and &&, or ||
Loops
• while loop (repeating if, condition checked at start):Format: while (expression) {statement;}
• for loop (for lists): Format: for (initial-stmt; cond; interation-stmt) {statement;}
Ex: for (i=0; i<10; i++) {statement;}• do...while loop (condition checked at end):
Format: do {statement;} while (expression);• switch (nested if...else):
Format: switch (expression){ case const1 {statement;break;} case const2 {statement;break;} }
Examples • Summation
int main() { int i=1, sum=0; for (i=1;i<=10;i++) { sum=sum+i; } printf("The sum is: %d\n",sum);}
• Switchswitch (month) { case 1 : case 3 : case 5 : case 7 : case 8 : case 10 : case 12: printf("31 days\n"); break; case 2: printf("28 or 29 days\n"); break; case 4 : case 6 : case 9 : case 11 : printf("30 days\n"); break;}
Pointers
• A variable is stored in a certain memory location or address
• Pointers allow to manipulate these addresses explicitly• Declaration: add a star to the type you want to point to
Ex: int *a;declares variable of type int that holds the address (a pointer to) an int
• Two operators:- & operator: "address of", can be applied to any variable, result has "one more star"- * operator: "dereference", accesses the object that the pointer points to, can only be applied to pointers, result has "one less star"
Pointer examples• int main() {
int i=5,j=2,z=3; //regular variables int *ip; //pointer declaration
ip = &i; //pointer now points to location of i j = *ip; //accesses value of object; j now has value 5 *ip = 7; // }
• Do not confuse notation:int *a declares the pointer;* operator ("content-of") dereferences ("makes less of a pointer")
• Can assign pointer values to other pointers:int *ip2; ip2=ip; // ip2 points to the same location as ip
Why pointers?• Consider swapping two values:
void swap(int x, int y){ int temp; temp=x; x=y; y=temp;}
int main() { int a=3,b=5; swap(a,b); printf("a is %d, b is %d\n",a,b);}
•Result: a is 3, b is 5! What went wrong?C is "pass by value", the called function cannot manipulate the original variables
A correct swap
• Cure: pass pointers and not variables:
void swap(int *px, int *py){ int temp; temp=*px; *px=*py; *py=temp;}
int main() { int a=3,b=5; swap(&a,&b); printf("a is %d, b is %d\n",a,b);}
• Pointers are most useful for passing data between functions
Arrays
• Often we need to manipulate large vectors or matrices of data
• Arrays allow to refer to a number of instances of the same nameEx: int data[5];declares an integer array of length 5
• Note: in C arrays are zero-indexed - numbering begins at zero!!
• data[expr] accesses elements of the array where expr evaluates to an integer
• Careful: there is no range checking. Only access elements 0 to N-1 for an array of size N.
• Multidimensional arrays:int data[N][M][L];
Arrays and Pointers• An integer array a is just a pointer, it is of type (int *).
• a points to first memory location of the array.
int *ip;ip=&a[0]; // sets ip to point to element zero of a
(ip+i) points to the i-th element
a[i] and *(ip+i) are equivalent! ip[i] and *(ip+i) are equivalent!
• Since an array is a pointer it can be manipulated by a function:Ex: void func (int *a){} int main (){ int b[3]={85,6,7}; func(b); }
Note: declare function to accept pointer!
What is the output?• int main(){
int a[4] = { 0, 1, 2, 3};
int *pa;
pa = a+1;
printf ("%ld\n", *pa);
printf ("%ld\n", pa[2]);
pa++;
printf( "%d\n",pa[0]);
scanf("%d", pa+1);
printf("You typed: %d\n",a[3]);
}1326You typed: 6
Structured Data Types
• The structure mechanism allows to aggregate variables of different types:
struct complex { double real; double im;}
void func(){ struct complex a,b; a.real=3; a.im=5; b=a;}
• "." is the member operator; connects structure and member
File I/O• Use fprintf or fscanf for input/output from/to files• Accessing files requires first the allocation of a file pointer:
FILE *results;
then opening the file for read/write/append withresults=fopen("data.dat","w"); or "r" or "a"
• Write to file (formatted output): fprintf(results, "format string\n", var1, var2, var3);
• Read from file (formatted input): fscanf(results, "format string\n", &var1, &var2, &var3);
Note: fscanf expects a location for the data, hence the &-operator.
• Finally: fclose(results);
• Note: standard input/output are handled as files; printf/scanf are just special cases of fprintf/fscanf applied to stout/stdin
Dynamic memory allocation
• Often we do not know the amount of required memory at compilation time (eg. variable size problem)
• int data[size] is a static array cannot change its size
• Need to allocate memory dynamically, "on the fly"• malloc(size): allocates size bytes and returns a pointer to the allocated
memory (or new in C++/Java)• free(ptr): frees the memory space pointed to by ptr• Example:
#include <stdlib.h>
int *data; int length=1000;data = malloc(sizeof(int)*length); //allocates int arrayfree(data);
Dynamic memory allocation
• If malloc is unable to allocate memory, it returns NULL pointer; good to check whether malloc was successful:
if(ip==NULL) { printf("out of memory\n"); exit(1);}
• It is possible to extend allocated memory:
datanew = realloc(data, sizeof(int)*(length*2));
creates contiguous block in memory; appends to existing data
Multidimensional arrays• To allocate multidimensional arrays, we use pointer to pointers:
#include <stdlib.h> int **array; array = malloc(nrows * sizeof(int)); if(array == NULL) { fprintf(stderr, "out of memory\n"); exit(1);} for(i = 0; i < nrows; i++) { array[i] = malloc(ncolumns * sizeof(int)); if(array[i] == NULL) { fprintf(stderr, "out of memory\n"); exit(1);}
}
• Can access like static array:array[i][j];
Tips for compiling• Compiling has three stages:
1) preprocessing 2) compile to object code (.o) 3) link all pieces and create executable
• Compiler options help control the process (see man gcc).All options start with -, some important options are:
-o: name of executable-O, -O2: turn on optimizer-I: additional search path for include-files (.h)-c: create only object code, do not link (for larger projects)-l: link library, e.g -lm for link to math library-L: additional search path for library-files-g: produce debugging info (for gdb or ddd)-Wall: turn on all warnings
Preprocessor statements• #include inserts the entire content of a file, verbatim.
#include "filename": searches for file in current directory#include <filename>: searches standard paths, typically for standard library header files
• #define allows to set up macros#define SIZE 10: the preprocessor replaces all occurrences of SIZE with 10.
- Makes global changes easier- Makes programs easier to read
• Conditional compilation : #ifdef name … #endifcontrol with -Dname at compilation
Working with libraries
• Libraries provide convenient access to additional functions
• Ex: sin(x), cos(x), exp(x) are all in the math library
• To access these functions, first include the corresponding header file (eg. math.h), then link the library with -lm when compiling
• We will use libraries like the GNU scientific library libgsl.a In this case:1) include <gsl/gsl_sf_bessel.h> (in code) 2) gcc prog.c -o prog -lm -lgsl -I/usr/local/lib
(on hyper.phas.ubc.ca)
Note: each library is searched only once, so the order matters!
Example: random number generator
#include <stdio.h>
#include <gsl/gsl_rng.h> // include header files
int main () { const gsl_rng_type * T; // define pointer to rng typegsl_rng * r; // define pointer to rng double u;gsl_rng_env_setup(); // reads env variables (seed)T = gsl_rng_default; // sets default rng r = gsl_rng_alloc (T); // returns pointer to rng Tu = gsl_rng_uniform (r); // samples from the rngprintf ("%.5f\n", u); } gsl_rng_free (r); // free up memoryreturn 0; }
Other libraries
• -lmpich: message passing interface (MPI) for parallel code
• -lfftw: fast fourier transforms
• -llinpack: linear algebra
• -lblas: basic linear algebra
•… and many more
The make utility• make is a powerful UNIX tool to manage the development of larger
projects• Executables are viewed as targets that have dependencies• A Makefile consists of definitions of one or more targets and how to
"make" them• Each target definition contains:
1. name of the target, followed by : 2. list of dependencies 3. set of actions that define how to make the target
• Example: prog1: prog1.c
gcc -g -O prog1.c -o prog1
Note: all lines stating actions MUST begin with a TAB to compile, simply type "make"
Makefiles continued
• For portability, make can access environment variables $(HOME) (note syntax)
• We can define our own macros:MYLIB = $(HOME)/libCCFLAGS= -g -O -I$(HOME)/include
(useful for automating the compilation process)• Note: to continue beyond one line use the \ (continuation construct)
FILES= a.c\ b.c\
c.c
• One can have generic targets:.c.o:
gcc $(CCFLAGS) $.c
tells make how to make a .o file from a .c file
A longer Makefile example
OBJ= prog1.o
CXXFLAGS=-g -O2 -lm -Wall
LINKFLAGS=-lm
CXX=gcc
.c.o:
$(CXX) $(CXXFLAGS) -c $*.c
prog1: $(OBJ)
$(CXX) $(LINKFLAGS) -o $@ $(OBJ)
clean:
rm -f *.o
rm prog1
Data visualization• gnuplot is a simple but powerful plotting tool• Plotting of functions:
f(x)=some functionp f(x)
• Plotting of data:p "data.dat" using ($1):($2)plots first column of data against second columndata can be processed by functions: eg. log($1):log($2)
• Print to file: set term post eps enhanced //switch output to encaps. psset out "plot.eps" //name of output filep "…" // plot commandset term x11 // switch output to screen
• Can automate using gnuplot scripts