780 likes | 913 Vues
CS 5600 Computer Systems. Lecture 2 : Crash Course in C “CS 5600? That’s the class where you write 1 million lines of C code.”. Overview. C: A language written by Brian Kernighan and Dennis Ritchie UNIX was written in C Became the first "portable " language
E N D
CS 5600Computer Systems Lecture 2: Crash Course in C “CS 5600? That’s the class where you write 1 million lines of C code.”
Overview • C: A language written by Brian Kernighan and Dennis Ritchie • UNIX was written in C • Became the first "portable" language • C is a typed, imperative, call-by-value language • “The C programming language -- a language which combines the flexibility of assembly language with the power of assembly language.”
Programming in C • Four stages • Editing: Writing the source code by using some IDE or editor • Preprocessing: Already available routines • Compiling: Translates source to object code for a specific platform • Linking: Resolves external references and produces the executable module • For the purposes of this class: • Editing (emacs or vim) • Compiling (gcc and make)
Example: Hello World in C 1:#include <stdio.h> 2: 3:intmain(intargc, char *argv[]) { 4:printf("Hello, world!\n"); 5:return0; 6: }
Line 1 1:#include <stdio.h> • During compilation, the C compiler runs a program called the preprocessor • The preprocessor is able to add and remove code from your source file • In this case, the directive #include tells the preprocessor to include code from the file stdio.h • Equivalent to import in Python or Java
Line 3 3:intmain(intargc, char *argv[]) { • This statement declares the main function • A C program can contain many functions but must have one main. • A function is a self-contained module of code that can accomplish some task • The intspecifies the return type of main • By convention, a status code is returned • 0 = success, any other value indicates an error
Line 4 4:printf("Hello, world!\n"); • printf is a function from a standard C library • Prints strings to standard output (usually the terminal) • Included by #include <stdio.h> • The compiler links code from libraries to the code you have written to produce the final executable
Line 5 5:return0; • Returns 0 from the current function • For main(), this is the return status of the program • Return value type must match the function definition • No statements after the return will execute
Data Types • A variables data type determines • How it is represented internally by the hardware • How it may be legally manipulated(operations allowed on that data type) • What values it may take on • Constants and variables are classified into 4 basic types • Character: char (1 byte) • Short: short (2 bytes) • Integer: int (usually 4 bytes), long int(usually 8 bytes) • Floating Point: float (usually 4 bytes), double (8 bytes) • All other data objects are built up from these fundamental types
char • What is a character? • A member of the character set • ASCII: American Standard Code for Information Interchange (128 characters) • Each character is internally represented using a number (e.g: A is 65) • Recognized types, sizes and ranges: • char: 1 byte (-128 ≤ x ≤ 127) • unsigned char: 1 byte (0 ≤ x ≤ 255)
More about char • ASCII character ‘2’ and the number 2 are not the same (2 != '2') • '2' is the character 2 (50 in ASCII) • 2 is the number 2 • As a result, '2' = 50 • Escape Sequence • Special characters denoted by ‘\’ followed by characters or hexadecimal code • \n new line • \t tab • \rcarriage return • \a alert • \\ backslash • \” double quote
short, int, long • A whole or integral number, not containing a fractional part • Recognized types, size and ranges: • short int: 2 bytes (-215 ≤ x ≤ 215 –1) • int: 4 bytes (-231 ≤ x ≤ 231 – 1, signed by default) • unsigned int: 4 bytes (0 ≤ x ≤ 232-1) • long longint: 8 bytes (-263 ≤ x ≤ 263 – 1, signed by default) • Expressible as octal, decimal or hexadecimal • Integer starting with 0 will be interpreted in octal (e.g: 010 is 8) • Integer starting with 0x will be interpreted in hexadecimal (0x10 is 16) • Negative numbers typically represented using two’s complement • What does short a = -7 look like in machine representation?
float, double • A number which may include a fractional part • Representation is an estimate (although at times, it may be exact) • 2.13 can be represented exactly • 1.23456789 x 1028 does not fit into a float • Hence number is truncated • Recognized types, sizes and ranges • float: 4 bytes (1 sign bit, 8 exponent bits, 24 fraction bits) • Range is -1e37 ≤ x ≤ 1e38 • double: 8 bytes (1 sign bit, 11 exponent bits, 53 fraction bits) • Range is -1e307 ≤ x ≤ 1e308 • long double: usually the same as double, sometimes 80 bits • You won’t be using floats or doubles in this class
Arithmetic Operators Assignment (=) a = b Addition (+) a + b Subtraction (-) a – b Multiplication (*) a * b Division (/) a / b Modulus (%) a % b Equal to a == b Not equal to a != b Less than a < b <or = to a <= b Increment a++ Decrement a-- • Order of precedence (highest to lowest) • Parenthesis • Multiplication, division, modulus • Addition, subtraction • Comparisons • Assignment
Bitwise Operators • intscan be viewed as collections of bits; C provides bitwise operations • Bitwise AND (&) a & b • Bitwise OR (|) a | b • Bitwise NOT (~) ~a • Bitwise XOR (^) a ^ b • Bitwise left shift (<<) a << b • Bitwise right shift (>>) a >> b • Examples: unsigned inta = 9; // 00001001 unsigned intb = 3; // 00000011 printf("9 & 3 is: %d\n", (a & b)); // 00000001 printf("9 << 3 is: %d\n", (a << b)); // 01001000
Constants • Constants are values written directly into program statements • Not stored in variables • Can assign constant values to variables unsigned int x = 122; char x = 'c'; • Variables can also be set as constants constintx = 1234; x = 5; // illegal, won’t compile
Numerical Constants • Integer constants • Default data type is int • If value exceeds int range, it then becomes long • Can force compiler to store value as long/unsigned using l/u suffixes longc = 0x0304lu; • Floating point constants • Default type of floating point is double • Can force type float during compilation by using decimal (e.g., 1.0) • Can also use scientific notation floatx = 1.3e-20;
Variables in C • Variable declaration (e.g., int x = 7;) • Associates data type with the variable name • Allocates memory of proper size • Cannot be re-declared within the same scope • Variable memory space initially contains junk, unless initialized int x; printf(“%i\n”, x); // who knows what will print • Variable names • Set of characters starting with [A-Z] or [a-z] or underscore • Period (.) is not allowed; no leading numbers; no reserved keywords • Case sensitive • Convention is lowercase used for variables and UPPERCASE for constants
Variable Types • Character variables: charfirst = 'c'; charsecond = 100; • Integer variables inta = 8; short unsigned intc = 2; • Floating point variables floatg = 3.4; doublee = -2.773;
Arrays • A data structure storing a collection of identical objects • Allocated memory space is contiguous • Identified using a single variable • The size is equal to the number of elements and is constant • Create an array called test_array which has 10 integer elements inttest_array[10]; intmy_array[2] = { 30, 10 }; • Array Elements • Referenced by name[index] (0-indexed; 2nd element is test_array[1] ) • Array bounds not checked intmy_array[10]; printf(“%i\n”, my_array[37]); // will compile and run, but may crash my_array[123] = 7; // will compile and run, but is wrong
Type Casting • What happens if you need to assign a variable of one type to a variable of a different type? • By default, operands converted to the longest type • char converts to int, int converts to float, float converts to double • Manual casting inty = (int) 3.14 * x; // legal double z = (double) y; // legal char * a = (char *) (3.14 * x); // won’t compile
Division and Modulus • Dividing ints always results in a new int printf(“%i\n”, 30 / 2); // 15 printf(“%i\n”, 31/ 2); // 15 printf(“%i\n”, 30 / 29); // 0 • Can force float division by casting printf(“%f\n”, 31/ (float) 2); // 15.5 • Modulus operator yields remainder of division printf(“%i\n”, 30% 2); // 0 printf(“%i\n”, 31% 2); // 1
sizeof() • Returns number of bytes required to store a specific data type. • Usage: intx = sizeof(<argument>); • Works with types, variables, arrays, structures: • Size of an intsizeof(int); // 4 • Size of a structure sizeof(structfoo); • Size of an array element: sizeof(test_array[0]); • Size of the entire array: sizeof(test_array); • Size of variable x: sizeof(x);
Pointers • Pointers are an address in memory • Includes variable addresses, constant addresses, function addresses... • Pointer is a data type just like any other (int, float, double, char) • On 32-bit machines, pointers are 4 bytes • On 64-bit machines, pointers are 8 bytes • Pointers point to a particular data type • The compiler checks pointers for correct use just as it checks int, float, etc.
Declaring Pointers • Use * to denote a pointer int *ptrx; // pointer to data type int float *ft; // pointer to data type float short *st; // pointer to data type short • Compiler associates pointers with corresponding data types • int * must point to an int, etc
Referencing/Dereferencing Pointers • How can you create a pointer to a variable? • Use &, which returns the address of the argument inty = 7; int*x = &y; // assigns the address of y to x • How can you get the value pointed to? • Dereference the pointer using * • Go to the address which is stored in x, and return the value at that address inty = 7; // y holds the value 7 int*x = &y; // x is the memory address of y intz = *x; // z now holds the value 7 (*a)++; // increments the value pointed to a *(a + 1); // accesses the value pointed to by the address (a + 1)
Pointer Quiz inty = 10; intx = y; y++; x++; • What is the value of y? 11 inty = 10; int*x = &y; y++; (*x)++; • What is the value of y? 12
Arrays and Pointers • Compiler associates the address of the array to/with the name inttemp[34]; • Array name (temp) is the pointer to the first element of array • To access the nth element of the array: • Address = starting address + n * size of element • Starting address = name of the array • Size of element = size of data type of array • array[n] de-references the value at the nth location in the array inttemp[10]; // Assume temp = 100 (memory address) temp[5] = *(100 + sizeof(int) x 5) = *(120)
Passing Arrays • Passing an array to a function passes a pointer • Hence arrays are always passed by reference intgeneral (intsize, intname []); //Expects a pointer to an int array intgeneral (intsize, int*name); //Expects a pointer to an int voidfoo(int a[]) { a[0] = 17; } intb[1] = { 5 }; foo(b); • What is the value of b[0]? 17
Functions and Pointers • Functions must return a value of the declared type • Just like variables, functions can return a pointer float*calc_area (float radius); • Function formal arguments may be of type pointer: doublecalc_size (int *stars); • For example, scanf takes in parameters as pointers: intscanf(const char *format, ...); // int*, int* scanf("%d%f", &x, &f);
Passing in Pointers • Why pass a variable address at all and complicate functions? • By design we can return only one value • Sometimes we need to return back more than one value • For example, consider scanf("%d %f", &x, &f); • Three values are returned (in x, f, and the return value) • Pointers allows us to return more than one value
Pointer Arithmetic • Pointers can be added to and also subtracted from • Pointers contain addresses • Adding to a pointer goes to next specified location (dep. on data type) • <data type> *ptr; • ptr + d means ptr + d * sizeof (<data type>); • For example int*ptr; • ptr + 2 means ptr + 2*sizeof(int) which is ptr + 8 char *ptr; • ptr + d means ptr + 2*sizeof(char) which is ptr + 2
Example #include <stdio.h> void main () { int*i; intj = 10; i= &j; printf("address of j is : %p\n", i); printf("address of j + 1 is : %p\n", i + 1); } • What is the output? $ ./a.out address of j is : 0xbffffa60 address of j + 1 is : 0xbffffa64 • Note that j + 1 is actually 4 more than j
Character Strings • A sequence of character constants such as “This is a string” • Each character is a character constant in a consecutive memory block • Each character is stored in ASCII, in turn is stored in binary • Character strings are actually character arrays • A string constant is a character array whose elements cannot change char *msg = "This is a string";
Strings as Arrays char *msg = "This is a string !"; • The variable msg is associated with a pointer to the first element • msg is an array of 19 characters • \0 is also considered a character • Appended to each string by the compiler • Used to distinguish strings in memory, acts as the end of the string • Also called the NULL character • Character pointers char *ptr; ptr= "This is a string"; • ptr is a char pointer containing the address of the first character (T)
String Functions #include <string.h> intstrcmp(char * a, char * b); // return 0 if strings are identical // otherwise, return is non-zero intstrlen(char * a); // returns count of characters, not including null char *strcpy(char * dst, char *src); // copies characters from b into a // returns the address of a // WARNING: a must have enough space to hold b!
Getting Numbers from Strings #include <stdlib.h> intatoi(const char *a); // converts an alphanumeric string to an // integer if possible (returns 0 on failure) doubleatof(const char * a); // converts string to double if possible int a = atoi("17"); //a is now 17 double b = atof("89.29393"); //b is now 89.29393
Structures • An aggregate data type which contains a fixed number of components • Declaration: structname { // a field // another field }; • For example structdob { intmonth; intday; intyear; }; • Each dob has a month, day, and year (ints) inside it
Using Structures • Declare variables using struct keyword • All internal variables are allocated space structdob d1, d2; • Access member values using ‘.’ notation d1.day = 10; d2.year = 1976; printf("%d\n", d2.year); • A structure can be assigned directly to another structure structdob d1, d2; d1.day = 10; d1.month = 12; d1.year = 1976; d2 = d1; // now d2 has the same values as d1 for its fields.
Operations on Structures • Cannot check to see if two structures are alike directly structdob d1, d2; if(d1 == d2) // WRONG !!! • To compare, we need to check every internal value • Cannot print structures directly • Must print one field at a time • Pointers to structures use the ‘->’ notation structdob *d1 = (structdob *) malloc(sizeof(struct dob)); d1->year = 1976; d1->day = 26; (*d1).month = 6;
A Little More on Structures • Can be initialized field by field or during declaration structdob d1 = {26, 6, 1976}; • Can create arrays of structures structdob d1[10]; // array of 10 structs dob • … and access them in the usual manner d1[1].day = 26; d1[1].month = 6; d1[1].year = 1976;
Making a structInto a Type • Type definition allows an alias for an existing type identifier typedef <type> <name>; • For example structdob_s { intday; intmonth; intyear; }; typedefstructdob_s dob; • Now you can simply dob my_dob; my_dob.year = 1984; Alternate form: typedefstructdob_s { intday; intmonth; intyear; } dob;
Memory Management • Two different ways to look at memory allocation • Transparent to user • Done by the compiler, OS • User-defined • Memory allocated by the user • Why allocate memory? • Required by program for permanent variables • Reserve working space for program • Normally maintained using a stack and a heap
Stack • Programs are typically given an area of memory called the stack • Stores local variables • Stores function parameters • Stores return addresses • On x86, the stack grows downwards • Functions are responsible for allocating and deallocating storage on the stack
Stack Frame Example Bytes 0 3 4 n name name_len Packet Stack X void foo(char * packet) { int offset = 0; char username[64]; intname_len; name_len = packet[offset]; memcpy(&username, packet + offset + 1,name_len); … } Callers return address X-4 int offset X-8 Christo Wilson char username[] X-72 15 intname_len X-76