C Language

Hello World

#include <stdio.h>

int main()
{
    printf("hello, world\n");
    return 0;
}

With arguments

#include <stdio.h>

int main(int argc, char* argv[]) {
    printf("arg count: %i\n", argc);
    for (int i=1; i<argc; i++) {
        printf("argv: %s\n", argv[i]);
    }
    return 0;
}

编译与运行

gcc hello.c
./a.out

comments

// comment

/*
multiline comments
*/

Command-line arguments

#include <stdio.h>

int main(int argc, char *argv[]) {
    int i;
    
    for (i=1; i<argc; i++) {
        printf("%s%s", argv[i], (i < argc-1) ? " ": "");
    }
    printf("\n");
    return 0;
}
  • argc: argument count
  • argv: argument vector

Includes

  • #include <xxx.h>: search in standard places, ex: /usr/include
  • #include "yyy.h": search in working dir

Variables

Data Types

Data Type Size Value Range Format
boolean 1
byte 1
char 1 -128 ~ 127 %d
unsigned char 1 0 ~ 255 %u
short 2+(dependent on complier) -32768 ~ 32767 %d
unsigned short 2+ 0 ~ 65535 %u
int short to long(dependent on complier) -2147483648 ~ 2147483647 %d
unsigned int short to long 0 ~ 2^32 %u
long 4+(dependent on complier) %ld
unsigned long 4+ %lu
float 4 3.4e-38 to 3.4e+38 %f
double 4 1.7e-308 to 1.7e+308

Type Cast

int x = 1;

// signed与unsigned互转,保持二进制表示不变,值可能改变
unsigned int ux = (unsigned int) x;

// 短类型转长类型
// 对于signed类型(Two's Complement编码)在左侧补最高位bit的值(sign extension)
// 对于unsigned类型,在左侧补0(zero extension)
long lx = (long) x;

// 长类型转短类型,截断高位,然后根据编码类型(signed or unsigned)解释数值
short sx = (short) lx;

Declaring and Instantiating Variables

// declarating
int year;
// instantiating
year = 2022;

// Declaring and instantiating simultaneously
int year = 2022 

// Constant
const float pi = 3.14;

Symbolic Constants

#define LOWER 0
#define UPPER 300
#define STEP 20

Enum Constants

// starts at 0, next 1, etc...
enum boolean { NO, YES };

// values are specified
enum escapes { BELL = '\a', BACKSPACE = '\b', TAB = '\t',
               NEWLINE = '\n', VTAB = '\v', RETURN = '\r' };

/* FEB = 2, MAR = 3, etc. */
enum months { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };

Array

int ndigit[10];
for (i = 0; i < 10; ++i) {
    ndigit[i] = 0;
}

// assigns values to first 5 data
int myarray[10] = {20, 30, 40, 50, 100};

int myarray[] = {20, 30, 40, 50, 100};

// size
size = sizeof(myArray) / sizeof(int)

2-D Array

// definition
char daytab[2][13] = {
    {0, 31, 28, ..., 31},
    {0, 31, 29, ..., 31}
};

// get value
daytab[i][j];

// passed to function
f(int daytab[2][13]) { ... }
f(int daytab[][13]) { ... } /* the number of row is irrelevant */
f(int (*daytab)[13]) { ... } /* a pointer to an array of 13 integers */

sizeof

  • size_t:unsigned interger, defined in <stddef.h>
#define NKEYS (sizeof keytab / sizeof(struct key))
#define NKEYS (sizeof keytab / sizeof(keytab[0]))

Character string

every character string has a ’\0’ at the end

char line[10];
char c;
c = 'a';
for (int i = 0; i < 10; ++i){
    line[i] = c;
    ++c;
}
printf("%s\n", line);

// equivalent
char pattern[] = "ould";
char pattern[] = { 'o', 'u', 'l', 'd', '\0' };

Strings

String name = "my text here";

name.charAt(0);
name.length();

Operator

Operators

Operator Description
+ Addition
- Substraction
* Multiplication
/ Division
% Modulus
++ Increment
Decrement
! Logical NOT
&& Logical AND
|| Logical OR
& Bitwise AND
| Bitwise OR
^ Bitwise EXCLUSIVE OR
~ Bitwise NOT
« Left shift
» Right shift

Conditional Expressions

z = (a > b) ? a : b; /* z = max(a, b) */

Control Flow

If-else

if (a > b) {
    z = a;
} else if {
    z = b;
} else {
    z = c;
}

if ((a==1) && (b==1)){ 
}

if ((a==1) || (b==1)){ 
}

if (!(a==1)){ 
}

Switch

switch (c) {
    case 'a':
        break;
    case 'b':
        break;
    case 'c':
        break;
    default:
        break;
}

For

for (int i=0; i<n; i++) {
    print(i);
}

for (int i=0; i<n; i++) {
    if (i>10) {
        break;
    }
}

for (int i=0; i<n; i++) {
    if (i<10) {
        continue;
    }
}

While

while (a < b) {
    a++;
}

Pointers

int x = 1, y = 2, z[10];
int *ip; /* ip is a pointer to int */
ip = &x; /* ip now points to x */
y = *ip; /* y is now 1 */
*ip = 0; /* x is now 0 */
ip = &z[0]; /* ip now points to z[0] */

/* pointer to void, can hold any type of pointer */
void *v;
v = &x;
/* cannot be dereferenced before cast */
printf("%d\n", *((int*) v));

Pointers and arrays

  • 一个array其实是一个指向首元素的pointer
  • arr[i]*(pa+i)是一样的
  • array name不是变量,无法被赋值,但是指针可以
  • 函数参数中传array name会在函数创建一个指向它的指针的局部变量

Pointers of pointers

char *lineptr[]; /* pointers to lines */

Pointers to functions

// comp is a pointer to a function that has two `void *` arguments
// and returns an `int`
int (*comp)(void *, void *)

Functions

int power(int m, int n); // declaration, called 'function prototype'

int main() {
    int i;
    for (i = 0; i < 10; ++i) {
        printf("%d %d %d\n", i, power(2, i), power(-3, i));
    }
}

int power(int base, int n) {
    int i, p;
    p = 1;
    for (i = 1; i <= n; ++i) {
        p = p * base;
    }
    return p;
}

or

// definition before caller
int power(int base, int n) {
    int i, p;
    p = 1;
    for (i = 1; i <= n; ++i) {
        p = p * base;
    }
    return p;
}

int main() {
    int i;
    for (i = 0; i < 10; ++i) {
        printf("%d %d %d\n", i, power(2, i), power(-3, i));
    }
}
  • all function arguments are passed ‘by value’.

Argument list

... means that the number and types of these arguments may vary

int printf(char *fmt, ...) 

use <stdarg.h> to step through an argument list

#include <stdarg.h>

/* minprintf: minimal printf with variable argument list */
void minprintf(char *fmt, ...) {
    va_list ap; /* points to each unnamed arg in turn */
    char *p, *sval;
    int ival;
    double dval;
    
    va_start(ap, fmt); /* make ap point to 1st unnamed arg */
    for (p = fmt; *p; p++) {
        if (*p != '%') {
            putchar(*p);
            continue;
        }
        switch (*++p) {
            case 'd':
                ival = va_arg(ap, int);
                printf("%d", ival);
                break;
            case 'f':
                dval = va_arg(ap, double);
                printf("%f", dval);
                break;
            case 's':
                for (sval = va_arg(ap, char *); *sval; sval++) {
                    putchar(*sval);
                }
                break;
            default:
                putchar(*p);
                break;
        }
    }
    va_end(ap); /* clean up when done */
}

Structures

// struct declaration
struct point {
    int x;
    int y;
};

// declare struct variable
struct point pt;
struct maxpt = { 320, 200 };

// refer struct members
printf("%d, %d", pt.x, pt.y);

// nested struct
struct rect {
    struct point pt1;
    struct point pt2;
};
struct rect screen;
printf("%d, %d", screen.pt1.x, screen.pt1.y);

// pointer to struct
struct point *pp;
pp = &pt;
printf("%d, %d", (*pp).x, (*pp).y);
printf("%d, %d", pp->x, pp->y);

Typedef

typedef int Length;

Union

union u_tag {
	int ival;
	float fval;
	char *sval;
} u;
  • a union is a structure in which all members have offset zero from the base, the structure is big enough to hold the “widest’’ member
  • It is the programmer’s responsibility to keep track of which type is currently stored in a union
  • A union may only be initialized with a value of the type of its first member;

Header files

  • Declaration: 声明变量或函数的类型
    • int sp;
    • double val[MAXVAL]
  • Definition:同时分配空间
    • extern int sp;
    • extern double val[]
  • extern variable只能被define一次,其他文件使用时需要declare才能用
  • static variable限定只有源文件能用
  • 通常将要共享的外部变量的declaratin放到一个header file中,在别的source file中include
  • 当included file变更时,所有include它的文件都要重新编译

calc.h

#define NUMBER '0'
void push(double);
double pop(void);

main.c

#include <stdio.h>
#include "calc.h"

int main() {
    ...
}

stack.c

#include <stdio.h>
#include "calc.h"

int sp = 0;
double val[MAXVAL];

void push(double) {
    ...
}
double pop(void) {
    ...
}

Macro

Conditional Inclusion

#if SYSTEM == SYSV
	#define HDR "sysv.h"
#elif SYSTEM == BSD
	#define HDR "bsd.h"
#elif SYSTEM == MSDOS
	#define HDR "msdos.h"
#else
	#define HDR "default.h"
#endif

#include HDR
#ifndef HDR
#define HDR

/* contents of hdr.h go here */

#endif

Input and Output

Standard IO

get/put character

获取下个字符:getchar/getc/fgetc

写入一个字符:putchar/putc/fputc

getchar

int getchar(void)

// routine
int c; // int, not char, for holding EOF(-1) reason
while((c=getchar()) != EOF) {
    
}

getline

// routine
#include <stdio.h>
#include <stdlib.h>

// or allocate memory via `malloc`
// size_t buf_size = 32;
// char *buffer = (char *) malloc(buf_size * sizeof(char));
size_t buf_size = 0;
char *buffer = NULL;
size_t read_size;

buffer = (char *) malloc(buf_size * sizeof(char));
if( buffer == NULL)
{
    perror("Unable to allocate buffer");
    exit(1);
}

while ((read_size = getline(&buffer, &buf_size, stdin)) > 0) {
    
}

printf

int printf(char *format, arg1, arg2, ...);

char* s = "hello world"
printf("%s", s);

scanf

int scanf(char *format, ...)

  • the arguments to scanf and sscanf must be pointers
// reads `25 Dec 1988` into day, monthname, and year
int day, year;
char monthname[20];
scanf("%d %s %d", &day, monthname, &year);

sscanf

int sscanf(char *string, char *format, arg1, arg2, ...)

while (getline(line, sizeof(line)) > 0) {
    if (sscanf(line, "%d %s %d", &day, monthname, &year) == 3) {
        printf("valid: %s\n", line); /* 25 Dec 1988 form */
    } else if (sscanf(line, "%d/%d/%d", &month, &day, &year) == 3) {
        printf("valid: %s\n", line); /* mm/dd/yy form */
    } else {
        printf("invalid: %s\n", line); /* invalid form */
    }
}

File

#include <stdio.h>

// fp is a pointer to a `FILE`
FILE *fp;

// `fopen` returns a pointer to a `FILE`
FILE *fopen(char *name, char *mode);

// freeing the file pointer
int fclose(FILE *fp);

fp = fopen(name, mode);
fclose(fp);

// returns the next char from the stream referred to by `fp`
int getc(FILE *fp);

// writes char `c` to the file `fp` and returns the char written
int putc(int c, FILE *fp);
    
// scanf from file instead of stdin
int fscanf(FILE *fp, char *format, ...);

// printf to file instead of stdout
int fprintf(FILE *fp, char *format, ...);

// reads the next input line from file `fp` into `line`
char *fgets(char *line, int maxline, FILE *fp);

// writes a string to a file
int fputs(char *line, FILE *fp);

patterns

char* name = "main.c";
FILE *fp = fopen(name, "r");
if (fp == NULL) {
    printf("cannot open file%s\n", name);
    exit(1);
}
fclose(fp);

Standard Libs

  • <stdio.h>:标准输入输出
  • <ctype.h>:Character Class Tests - isalnum(c),isalpha(c), etc…
  • <math.h>:数学运算
  • <unistd.h>:Unix标准库
  • <time.h>:时间相关
  • <limits.h>:整数类型常量
  • <float.h>:浮点类型常量

string

  • <string.h>
    • strcat(s, t): concatenate t to end of s
    • strcmp(s, t): compare to strings, return negative if s<t
    • strcpy(s, t): copy t to s
    • strlen(s): return length of s
    • strchr(s, c): return pointer to first c in s , or NULL if not present
    • strrchr(s, c): return pointer to last c in s , or NULL if not present

ctype

  • <ctype.h>
    • isalpha(c)
    • isupper(c)
    • islower(c)
    • isdigit(c)
    • isalnum(c)
    • isspace(c)
    • toupper(c)
    • tolower(c)

stdlib

  • <stdlib.h>
    • system(char* s): executes the command s
    • void *malloc(size_t n): obtain blocks of memory dynamically, returns a pointer to n bytes
    • free(p): frees the space pointed to by p

math

  • <math.h>
    • sin(x)
    • cos(x)
    • exp(x)
    • log(x)
    • pow(x, y): x^y
    • sqrt(x)
    • fabs(x): absolute value of x

Complie

gcc -Wall main.c # -Wall: enable all warnings

gcc -E main.c    # -E: preprocess
gcc -c helper.c  # -c: to produce object files

gcc -g main.c    # -g: to enable debugging with gdb
gcc -O main.c    # -O: to turn on optimization

gcc -lm  main.c  # The -lXXX flag tells the linker to look for libXXX.so or libXXX.a
gcc -I/foo/bar main.c # look for headers in the directory `/foo/bar`
gcc -L/foo/bar main.c # look for libraries in the directory `/foo/bar`

gcc -std=c89 main.c   # ISO C90标准,默认选项
gcc -std=c99 main.c   # ISO C99标准
gcc -std=c11 main.c   # ISO C11标准

查看动态链接库

ldd a.out

References