Basic C [1]#
P2M3 Requirements Clarification#
Some students are asking if they can use other methods to implement players and stock, piles.
Please follow the requirements listed on p2.pdf
(Selected):
…
Use a circular double linked list for the players;
Use a dynamic array to handle the stock and discard piles;
…
C Types#
Type Qualifier#
The most commonly-used qualifier in C is the const type qualifier.
Constant type qualifier can make one variable constant and it may help in some cases.
const int some_magic_number = 100;
const char *const my_str[2] = {"List1", "List2"};
You can also use the #define directive to define a constant:
#define PI 3.1415926
Scope of Variables#
Global variables: defined for all functions (outside the function or
static
)Warning
Never use non-constant global variables in VG151!
Further Reading: Static storage duration [2]
The storage duration is the entire execution of the program, and the value stored in the object is initialized only once, prior to main function. All objects declared static and all objects with either internal or external linkage that aren’t declared
_Thread_local
(since C11) have this storage duration.Local variables: defined only in functions
Type Classification [3]#
The C type system consists of the following types: (excluded some types that we don’t need in VG151)
the type
void
basic types
the type
char
signed integer types
standard:
signed char
,short
,int
,long
,long long
(since C99)
unsigned integer types
standard:
unsigned char
,unsigned short
,unsigned int
,unsigned long
,unsigned long long
(since C99)
floating-point types
real floating-point types:
float
,double
,long double
enumerated types
derived types
array types
structure types
function types
pointer types
Tip
There is no direct bool
type support in C11 standard.
Arithmetic Types#
(See arithmetic types for more details)
int x = 3;
float x = 1.0;
7 digits of precisiondouble c = 5.5;
13 digits of precision
Tip
When comparing two double
or float
, it’s safer to allow errors.
#include <math.h>
#include <limits.h>
float a,b;
// ...
if(abs(a - b) <= FLT_EPSILON){
printf("a and b are equal");
}
FLT_EPSILON
defined in limits.h
is helpful.
Characters#
Characters are enclosed in single quotes:
char a = 'a'
;Character are encoded using the American Standard Codes for In-formation Interchange (ASCII)
No
string
type. A string is viewed as an array of characters.Strings are enclosed in double quotes. Usually a string should ended up with a char
'0'
.Here are examples about how to initialize strings:
char c[] = "abcd";
char c[50] = "abcd";
char c[] = {'a','b','c','d','\0'};
char c[5] = {'a','b','c','d','\0'};
Displaying#
Comparing those two code snippets:
#include <stdio.h>
int main(){
printf("%d %f\n",7/3,7/3);
}
#include <stdio.h>
int main(){
printf("%d %f\n",7/3,7.0/3);
}
%d
means a signed integer here and%f
means a floating-point number here.The compiler would take
7/3
as an integer, and take7.0/3
as a floating-point number.
Tip
You can use suffix, if present, is one of f
, l
, F
, L
to define a “floating-point literal”.
f
,F
definesfloat
l
,L
defineslong double
Example:
printf("%f\n",7f/3);
For the format specifiers, see fprintf documentation.
Type Casting#
Basic syntax:
(type) variable
char a = (char) 100.111;
Thena
becomes'd'
Pay attention to the size and precision especially when dealing with mathematical operations.
Structures#
Basic struct
usage:
#include <stdio.h>
typedef struct _person {
char* name;
int age;
} person;
int main() {
person al={"albert",32};
person gil;
gil.name="gilbert";
gil.age=23;
struct _person so={"sophie",56};
printf("%s %d\n",al.name, al.age);
printf("%s %d\n",gil.name, gil.age);
printf("%s %d\n",so.name, so.age);
}
Combine with functions:
#include <stdio.h>
typedef struct _person {
char* name;
int age;
} person;
person older(person p,int a);
int main() {
person al = {"albert",32};
al = older(al,10);
printf("%s %d\n", al.name, al.age);
}
person older(person p,int a) {
printf("%s %d\n", p.name, p.age);
p.age += a;
return p;// A C function can only have one output.
}
Control Statements#
Basics on Conditional Statements#
No boolean type, 0 means False, anything else True
Boolean evaluation:
<, <=, >, >=, ==, !=
Not:
!
, short-circuit operators: and:&&
, or:||
Bit operations:
&, |, ^
Conditional Ternary Operator#
(Fewer lines, but not recommended in exams)
condition ? expression1 : expression2
Example:
#define MAX(a,b) a>=b ? a : b
if
and switch
#
if(x == 0) printf("zero\n");
else if(x == 1 || x == 2) printf("one or two\n");
else printf("not zero or one\n");
switch(x) {
case 0:
printf("zero\n");
break; // Don't forget the break!!!
case 1:
case 2:
printf("one or two\n");
break;
default:
printf("not zero or one or two\n");
break;
}
Random numbers#
When generating random numbers, usually we should add these two lines:
#include <stdlib.h>
#include <time.h>
To make the random number “random”, we could use srand(time(NULL))
.
srand()
seeds the pseudo-random number generator used by rand()
.
If rand()
is used before any calls to srand()
, rand()
behaves as if it was seeded with srand(1)
.
Each time rand()
is seeded with srand()
, it must produce the same sequence of values.
Pseudo-random integer value between 0 and RAND_MAX
, inclusive.
Loops#
while
and do ... while
loops#
int i = 0;
do {printf("%d",i);} while(i++ < 1);
i = 0;
do {printf("%d",i);} while(++i < 1);
i = 0;
while (i++ < 1) {printf("%d",i);}
i = 0;
while (++i < 1) {printf("%d",i);}
for
loops#
for(i = 0; i < n; i++)
printf("%d ",i);
i = 0;
for(; i < n; i++)
printf("%d ",i);
for(i = 0; i < n;){
printf("%d ",i);
i++;
}
for(i = 0; i<n;)
printf("%d ",i++);
break
and continue
#
Early exit of a loop:
break
Skip to the next loop iteration:
continue
Initialization [4]#
(Removed some advanced usage)
Initialization is quite complicated in C. (of course less complicated comparing to C++)
A declaration of an object may provide its initial value through the process known as initialization.
For each declarator, the initializer, if not omitted, may be one of the following:
= expression
= { initializer-list }
where initializer-list
is a non-empty comma-separated list of initializers (with an optional trailing comma), where each initializer has one of three possible forms:
expression
{ initializer-list }
Explicit Initialization#
Examples:
int y[4][3] = { // array of 4 arrays of 3 ints each (4x3 matrix)
{ 1 }, // row 0 initialized to {1, 0, 0}
{ 0, 1 }, // row 1 initialized to {0, 1, 0}
{ [2]=1 }, // row 2 initialized to {0, 0, 1} (advanced usage)
}; // row 3 initialized to {0, 0, 0}
char str[3] = "abc"; // str has type char[3] and holds 'a', 'b', 'c'
char str[] = "abc"; // str has type char[4] and holds 'a', 'b', 'c', '\0'
int a[3] = {0}; // valid C and C++ way to zero-out a block-scope array
int a[3] = {}; // valid C++ way to zero-out a block-scope array; valid in C since C23 (not valid in C11)
const char *const my_str[] = {"List1", "List2"}; // my_str is a const array of string
struct point {double x,y,z;} p = {1.2, 1.3}; // p.x=1.2, p.y=1.3, p.z=0.0
struct point {double x,y,z;} p = {.y=1.3}; // p.x=0.0, p.y=1.3, p.z=0.0
Implicit Initialization#
If an initializer is not provided:
objects with
static
storage duration are empty-initializedother objects are initialized to indeterminate values
For example, consider the result of the following code:
#include <stdio.h>
int glb_array2[10];
int main(){
int local_array[10];
static int glb_array1[10];
printf("%d\n", local_array[0]);
printf("%d\n", glb_array1[0]);
printf("%d\n", glb_array2[0]);
}
The result would be:
1826935528
0
0
Apparently the first result is undetermined.
It’s a good habit to initialize variables when declaring them.
Dynamically allocate a 2D array [5]#
Like this:
int (*arr)[M] = NULL;
arr = malloc(sizeof(int[N][M]));
arr
is pointer to int[M]
.
Use like arr[0][M-1];
.
And free(arr);
.
Good Luck#
Hope you can do well!