Professor G. slides adapted by G. Sandoval from slide by -Gavitt
Just kidding, it takes longer than that! But we’ll cover the basics in class today For more details, you can consult:
▪ Learn C DOT ORG: http://www.learn-c.org
Copyright By PowCoder代写 加微信 powcoder
▪ Zed Shaw, Learn C the Hard Way
This book has lots of challenging exercises. https://www.amazon.com/Learn- Hard-Way-Practical-Computational/dp/0321884922
▪ and , The C Programming Language https://archive.org/details/TheCProgrammingLanguage
▪ Head first C: I enjoyed this book when I was teaching C about 5 years ago. https://www.amazon.com/Head-First-C-Brain-Friendly- Guide/dp/1449399916
Let’s write a C program that prints the string “Hello world”
Include file: similar to “import” in Python
Declaration of function “main”, returning type “int”
Calling the printf function with a string parameter
Each statement must end with a semicolon
Return the value 0
$ gcc hello.c -o hello $ ./hello
Hello, world
Where exactly do you run gcc?
At the command line
On OS X, this is in the Terminal App (/Applications/Utilities)
In Linux, xterm, gnome-terminal, etc. are all fine
On Windows – use the bash shell
Invoking gcc on hello.c did the following things:
1. Called the C preprocessor (cpp) on hello.c
2. cpplookedforstdio.hinthedefaultincludepath (a set of directories where header files live) and then recursively called itself on stdio.h
3. The output of that process was pasted into hello.c, and the result was compiled by gcc into an executable binary
Remembering and reproducing the commands to compile a project is tedious
Larger projects may have multiple files, many compilation options, external libraries, etc.
To manage this complexity we can use a Makefile
Instead of calling gcc, we can instead just do: $ make hello
cc hello.c -o hello
The make command has some built-in rules that understand how to compile basic C and C++ programs
The make command will check whether the file “hello” exists and is newer than the file “hello.c”; if not, it will try to build “hello” using “hello.c”
For more complex rules, or to build things that make doesn’t natively understand how to create, we use a Makefile:
CFLAGS=-Wall -g
rm -f hello
Extra compile flags. Will be treated as if passed as args to gcc
Now we can have make clean up for us: $ make clean
rm -f hello
For more complex rules, or to build things that make doesn’t natively understand how to create, we use a Makefile:
CFLAGS=-Wall -g
rm -f hello
Now we can have make clean up for us: $ make clean
rm -f hello
The name of our new build target
For more complex rules, or to build things that make doesn’t natively understand how to create, we use a Makefile:
CFLAGS=-Wall -g
rm -f hello
Now we can have make clean up for us: $ make clean
rm -f hello
The command to run to build the target
For more complex rules, or to build things that make doesn’t natively understand how to create, we use a Makefile:
CFLAGS=-Wall -g
rm -f hello
The command to run to build the target
Now we can have make clean up for us: $ make clean
rm -f hello
NOTE: this must be a tab character, not spaces!
– New program:
– Write a C program that prints your age and height.
– No need to input anything, you can hardcode both age and height.
– Compile and run it!
Variable type Variable name
Initial value
char A single byt, capable of holding one character in the local
character set
int An integer, typically reflecting the natural size of integers in the local
float Single precision floating point
Double Double precision floating point
-128 to 127
-2147483648 To 2147483647
32 bit IEEE floating point 32 bit IEEE floating point
Note: some of these ranges are different on different platforms and implementations of C. Here I’m giving the ranges for 32-bit x86, which is what we’ll be working with this semester. More precise details can be found by consulting the C language specification.
Arithmetic:
▪ + (plus), – (minus), / (division), * (multiplication),
% (modulus)
▪ && (and), || (or), ! (not)
Relational
▪ < (less than), > (greater than), >= (greater or equal), <= (less or equal), == (equal), != (not equal)
Binary arithmetic
▪ ~x: one's complement (i.e., flip all bits) ▪ x << n: shift x left by n bits
▪ x >> n: shift y right by n bits
▪ x & y: bitwise AND of x and y
▪ x | y: bitwise OR of x and y
▪ x ^ y: bitwise XOR of x and y
Branching:
▪ if (condition) { statements
else if (condition) {
statements
statements
Branching:
▪ switch (expression) { case 1:
statements
break; case 2:
statements
break; default:
statements
while (condition) { statements
statements
} while (condition);
for (init ; condition ; update) { statements
for (i = 0; i < 100; i = i + 1) {
printf("This is iteration %d\n", i); }
Breakout:
"Write a program that prints the numbers from 1 to 100. But for multiples of three print “Fizz” instead of the number and for the multiples of five print “Buzz”. For numbers which are multiples of both three and five print “FizzBuzz”."
All code in C lives in a function Declaring a function is simple:
int add(double x, double y) { return x + y;
Calling it is simple too
int result = add(4.9, 12.1);
All code in C lives in a function Declaring a function is simple:
Return type
Function name
int add(double x, double y) { return x + y;
Parameters
Calling it is simple too
int result = add(4.9, 12.1);
x = y: simple assignment
Note: x = y is an expression, and evaluates to
the right hand side. So, you can do things like if ((x = y) > 0) …
which will assign x the value of y and branch if y is greater than 0
x += y: same as x = x + y
▪ -=, *=, /=, <<=, >>=, %=, &=, |=
(Pre/Post) Increment/decrement ▪ x++: evaluate x, then increment it
▪ ++x: increment x, then evaluate it
▪ x–: evaluate x, then decrement it
▪ –x: decrement, then evaluate it
#include
int main() { int x = 0;
if (x++ > 0) {
// 1 will be printed ?
if (x > 0) {
// 2 will be printed ? }
if (++x > 0) {
// 3 will be printed ?
if (x > 0) {
// 4 will be printed ? }
return 0; }
#include
int main() { int x = 0;
if (x++ > 0) {
printf(“This will not be printed\n”);
if (x > 0) {
printf(“This will be printed\n”); }
if (++x > 0) {
printf(“This will be printed\n”); }
if (x > 0) {
printf(” This will be printed \n”);
return 0; }
Arrays in C are fixed-length (their size must be specified at compile time)
To declare an array: int x[10];
Then individual elements are accessible as x[i] where i is an integer
Array Bounds
Unlike higher-level languages, C does not check array bounds
▪ In some simple cases, the compiler can detect when you access an out-of-bounds element, but it’s not part of the language
Programming in C requires you to be very careful when programming; there are basically no safety features
cosimo:lec2 moyix$ gcc oob.c -o oob
oob.c:6:5: warning: array index 10 is past the end of the array (which contains5 elements) [-Warray-bounds]
x[10] = 9;
oob.c:4:5: note: array ‘x’ declared here int x[5];
oob.c:8:28: warning: array index 10 is past the end of the array (which contains 5 elements) [-Warray-bounds]
printf(“x[10] = %d\n”, x[10]);
oob.c:4:5: note: array ‘x’ declared here int x[5];
2 warnings generated. cosimo:lec2 moyix$ ./oob x[10] = 9
Segmentation fault: 11
Strings in C are a special case of arrays
A C string is an array of characters, where the
final element in the array is NULL (‘\0’) So:
char hello[] = “hi”;
is the same as
char hello[] = {‘h’, ‘i’, ‘\0’};
C has a special kind of variable called a pointer Pointers hold the address of another variable To declare:
Two new operators:
&x : get the address of x
*p : access the value of the pointed-to variable
(called dereferencing)
0xbff9cb4c 0xbff9cb50 0xbff9cb54
pNULL y20x10 0xbff9cb4c 0xbff9cb50 0xbff9cb54
At the start, x = 10, y = 20, p = 0x0
Pointer at 0xbff9cb4c
has value 0xbff9cb54 and points to var with value 10
After assigning to *p, x = 5
Pointer at 0xbff9cb4c
has value 0xbff9cb50 and points to var with value 20
After assigning to *p, y = 50
pNULL y20x10 0xbff9cb4c 0xbff9cb50 0xbff9cb54
0xbff9cb4c
0xbff9cb54
y 20 0xbff9cb50
At the start, x = 10, y = 20, p = 0x0
Pointer at 0xbff9cb4c
has value 0xbff9cb54 and points to var with value 10
After assigning to *p, x = 5
Pointer at 0xbff9cb4c
has value 0xbff9cb50 and points to var with value 20
After assigning to *p, y = 50
x 10 0xbff9cb54
0xbff9cb4c
0xbff9cb54
y 20 0xbff9cb50
At the start, x = 10, y = 20, p = 0x0
Pointer at 0xbff9cb4c
has value 0xbff9cb54 and points to var with value 10
After assigning to *p, x = 5
Pointer at 0xbff9cb4c
has value 0xbff9cb50 and points to var with value 20
After assigning to *p, y = 50
x 10 0xbff9cb54
0xbff9cb4c
0xbff9cb54
y 20 0xbff9cb50
At the start, x = 10, y = 20, p = 0x0
Pointer at 0xbff9cb4c
has value 0xbff9cb54 and points to var with value 10
After assigning to *p, x = 5
Pointer at 0xbff9cb4c
has value 0xbff9cb50 and points to var with value 20
After assigning to *p, y = 50
x 5 0xbff9cb54
0xbff9cb4c
0xbff9cb54
y 20 0xbff9cb50
At the start, x = 10, y = 20, p = 0x0
Pointer at 0xbff9cb4c
has value 0xbff9cb54 and points to var with value 10
After assigning to *p, x = 5
Pointer at 0xbff9cb4c
has value 0xbff9cb50 and points to var with value 20
After assigning to *p, y = 50
x 5 0xbff9cb54
0xbff9cb4c
0xbff9cb50
y 20 0xbff9cb50
At the start, x = 10, y = 20, p = 0x0
Pointer at 0xbff9cb4c
has value 0xbff9cb54 and points to var with value 10
After assigning to *p, x = 5
Pointer at 0xbff9cb4c
has value 0xbff9cb50 and points to var with value 20
After assigning to *p, y = 50
x 5 0xbff9cb54
0xbff9cb4c
0xbff9cb50
y 20 0xbff9cb50
At the start, x = 10, y = 20, p = 0x0
Pointer at 0xbff9cb4c
has value 0xbff9cb54 and points to var with value 10
After assigning to *p, x = 5
Pointer at 0xbff9cb4c
has value 0xbff9cb50 and points to var with value 20
After assigning to *p, y = 50
x 5 0xbff9cb54
0xbff9cb4c
0xbff9cb50
y 50 0xbff9cb50
At the start, x = 10, y = 20, p = 0x0
Pointer at 0xbff9cb4c
has value 0xbff9cb54 and points to var with value 10
After assigning to *p, x = 5
Pointer at 0xbff9cb4c
has value 0xbff9cb50 and points to var with value 20
After assigning to *p, y = 50
x 5 0xbff9cb54
0xbff9cb4c
0xbff9cb50
y 50 0xbff9cb50
At the start, x = 10, y = 20, p = 0x0
Pointer at 0xbff9cb4c
has value 0xbff9cb54 and points to var with value 10
After assigning to *p, x = 5
Pointer at 0xbff9cb4c
has value 0xbff9cb50 and points to var with value 20
After assigning to *p, y = 50
x 5 0xbff9cb54
■ Call-by-value: Changes made to arguments passed to a function aren’t reflected in the calling function
■ Call-by-reference: Changes made to arguments passed to a function are reflected in the calling function
■ C is a call-by-value language
■ To cause changes to values outside the function, use pointers
■ Do not assign the pointer to a different value (that won’t be reflected!)
■ Instead, dereference the pointer and assign a value to that address
■ Example:
■ Write a function called swap that given two integers it swaps it’s values:
■ Example:
■ Write a function called swap that given two integers it swaps it’s values:
■ Example:
■ Write a function called swap that given two integers it swaps it’s values:
Variables of different types can be converted to one another
For example: prints
int x = 10;
float y = x;
printf(“x = %d, y = %f\n”, x, y);
x = 10, y = 10.000000
The details of this are somewhat complicated, but a general rule is that things can be converted automatically as long as you aren’t losing precision
Some conversions need an explicit cast – a way of telling C that you really do want that conversion
For example:
int x = 90000;
short y = (short) x;
printf(“x = %d, y = %d\n”, x, y); prints
x = 90000, y = 24464
Pointers of one type can be cast to another type
As usual, C does not stop you from shooting yourself in the foot with this
But it does let you do some handy things too!
POLY is 1498173264
POLY is 1498173264
POLY is 1498173264
“POLY” = {‘P’, ‘O’, ‘L’, ‘Y’, ‘\0’}
= 0x50, 0x4f, 0x4c, 0x59, 0x00
= 0x594c4f50 = 1498173264
1498173264 is POLY
Sometimes we want more complicated data types than just int, char, etc.
For this we can define a struct – an aggregate type that contains several fields
If you have a pointer to a structure, you can dereference the pointer and access its member in one step:
struct Person *p = &q; p->age = 64;
file, sh.c, creates several structs and casts between them in order to mimic inheritance
The switch statement uses the type field of a struct cmd, which they all share, to decide the correct type to cast to
You can make pointers point to anything you like, really
it’s something sensible
Sometimes this is actually useful, particularly
when writing code that talks directly to hardware
Though you are responsible for making sure
Writes 10 at address 0x12345678
Arrays and pointers have a special relationship in C
An array can be treated as a pointer in most contexts, and vice versa
If you hand an array of type T to something that expects a pointer to type T, it’s treated as if it were a pointer to the first element of the array
You can do arithmetic on pointers
Given a pointer P of type T, P + N will point to
the memory at address P + (N * sizeof(T)) For example:
=> Prints “*p = 3”
You may have noticed that x[2] and *(p + 2) refer to the same element
This is not an accident!
In fact, we can use array index notation with
pointers as well:
=> Prints “p[2] = 3”
Recall that I said C only supports fixed-length arrays
So how do you deal with variable amounts of data?
To allocate: p = malloc(size in bytes) – returns a pointer to a memory region that
you can then assign to a variable of whatever
type you like
To free: free(p)
Memory Management Rules
■ Malloc what you free, free what you malloc
■ client should free memory allocated by client code
■ library should free memory allocated by library code
■ Number mallocs = Number frees
■ Number mallocs > Number Frees: definitely a memory leak
■ Number mallocs < Number Frees: definitely a double free
■ Free a malloced block exactly once
■ Should not dereference a freed memory block
■ Don’t put too much data on malloced memory ■ Make sure you allocate extra space for NULL on strings
Stack Vs Heap Allocation
■ Local variables and function arguments are placed on the stack
■ deallocated after the variable leaves scope
■ do not return a pointer to a stack-allocated variable!
■ do not reference the address of a variable outside its scope!
■ Memory blocks allocated by calls to malloc/calloc are placed on the heap
■ Globals, constants are placed elsewhere
■ Example:
■ // a is a pointer on the stack to a memory block on the heap
■ int* a = malloc(sizeof(int));
struct list { int data;
struct list *next; };
struct list * list_insert(struct list *head, int data) { /* Write code for insert */
struct list * list_insert(struct list *head, int data) { struct list *new = malloc(sizeof(struct list)); new->data = data;
new->next = head;
return new; }
struct list * list_insert(struct list *head, int data) { struct list *new = malloc(sizeof(struct list)); new->data = data;
new->next = head;
return new; }
Memory allocation
sizeof operator gets the size of a type
Void list_delete(struct list *head) {
/* Write code for freeing all the nodes on the list and */
Freeing memory
List entry at 0x7b6517d0 has data 38 List entry at 0x7b6517c0 has data 36 List entry at 0x7b6517b0 has data 34 List entry at 0x7b6517a0 has data 32 List entry at 0x7b651790 has data 30 List entry at 0x7b651780 has data 28 List entry at 0x7b651770 has data 26 List entry at 0x7b651760 has data 24 List entry at 0x7b651750 has data 22 List entry at 0x7b651740 has data 20 List entry at 0x7b651730 has data 18 List entry at 0x7b651720 has data 16 List entry at 0x7b651710 has data 14 List entry at 0x7b651700 has data 12 List entry at 0x7b6516f0 has data 10 List entry at 0x7b6516e0 has data 8 List entry at 0x7b6516d0 has data 6 List entry at 0x7b6516c0 has data 4 List entry at 0x7b6516b0 has data 2 List entry at 0x7b6516a0 has data 0
Why did we have to use the extra to_delete variable?
Function pointers
Code in multiple files
Linking to external libraries
Preprocessor macros
Some modifiers: static, const, volatile, extern
Ternary operator, variable-argument functions (e.g., printf)
C is a very low level language. You can address memory directly.
We saw a lot of great features of C
We saw a lot of ways you can shoot yourself in
the foot with C
You will need to know/learn C for this class.
int main() {
char w[strlen(“C
programming”)];
strcpy(w,”C programming”); printf(“%s\n”, w);
int main() {
char w[strlen(“C
programming”)];
strcpy(w,”C programming”);
strlen returns the length of printf(“%s\n”, w);
return 0; }
the string not including the null character, so we end up
writing a null byte outside the bounds of w.
C Libraries
string.h: Common String/Array Methods
■ One the most useful libraries available to you
■ Important usage details
regarding arguments:
■ prefixes: str -> strings, mem -> arbitrary
memory blocks.
■ ensure that all strings are ‘/0’ terminated!
■ ensure that dest is large enough to store
■ ensure that src actually contains n bytes!
■ ensure that src/dest don’t overlap!
string.h: Common String/Array Methods
■ Copying:
■ void* memcpy (void* dest, void* src, size_t n): copy n bytes of
src into dest, return dest
■ char* strcpy(char* dest, char* src): copy src string into dest,
return dest
■ Concatenation:
■ char * strcat (char * dest, char* src): append copy of src to end
of dest, return dest
■ Comparison:
■ int strcmp (char * str1, char * str2): compare str1, str2 by
character (based on ASCII value of each character, then string length), return comparison result
str1 < str2: -1,
str1 == str2: 0,
str1 > str2: 1
string.h: Common String/Array Methods (Continued)
■ Searching:
■ char* strstr (char * str1, char * str2): return pointer
to first occurrence of str2 in str1, else NULL
■ char* strtok (char * str, char * delimiters): tokenize
str according to delimiter characters provided in delimiters, return the next token per successive stroke call, using str = NULL
■ size_t strlen ( const char * str ): returns length of the
string (up to, but not including the ‘\0’ character)
■ void * memset (void* ptr, int val, size_t n ): set first
n bytes of memory block addressed by ptr to val (use this for setting bytes only; don’t use to set int arrays or anything else!)
stdlib.h: General Purpose Functions
■ Dynamic memory allocation: ■ malloc, calloc, free
■ String conversion:
■ int atoi(char* str): parse string into integral value (return 0 if not parsed)
■ System Calls:
■ void exit(int status): terminate calling process, return status to parent process
■ void abort(): aborts process abnormally
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com