標準的C語言main寫法:

  1. 回傳類型不建議用void,而用int。
  2. 不建議用main(),而用main(void) 或 main(int argc, char *argv[])。
  3. 回傳類型寫int,然後不寫return 0;還是可以編譯過,只有main限定,但還是寫出來比較好。
雖然上述不建議的地方,C語言還是可以編譯過,但是要和其他人協作,是需要規範標準規格,所以嚴格遵守寫作規則是相當重要的。C語言規格書: C99 - C18
在 C 語言的物件就指在執行時期,資料儲存的區域,可以明確表示數值的內容
linux kernel有許多地方是由C語言撰寫而成,kernel的編譯器會影響OS的效能。所以C語言除了熟悉語法外,演算法和debug能力是極其重要的。Debug工具: GDB

數值和字串的轉換

數值轉字串: snprintf第一個參數是被寫入的地方, 第二個是限制寫多長,第三是數值類型, 第四是數值變數。
code裏有兩個sample, int和float的, 注意float的小數點位數記得設定。

字串轉數值: sscanf第一個參數放字串變數, 第二個放要轉成的類型, 第三個放要放入變數的記憶體位址
code裏有四個sample, 前兩個爲int和混合string的, 後兩個爲float和混合string。


String

package:
#include <string.h>

string length:
size_t strlen ( const char * str );

It will return how many characters in string.(without '\0')
(It takes one byte to hold one character.)
If a string contain "I am fine."
#include <stdio.h>
#include <string.h>
#define STR "I am fine."

int main(void) {

// strlen()
printf("%zd", strlen(STR));
// output 10

// sizeof
printf("%zd", sizeof STR);
// output 11 (contain '\0' means null character.)

sizeof
is an operator.

printf

The "printf" will return number of characters.

If sentence is too long. You can type '\' to split sentence.
 // example
printf("split \
first line.");
//output
split first line. 

strncpy


gcc參數

ref
gcc參數參考資料

gcc link dll

dllName: this_dll_sample.dll
gcc sample.c -lthis_dll_sample 

Displaying Octal and Hexadecimal

Write pound sign in center of percent sign and number notation.
// print octal and hexadecimal
printf("%#o, %#x\n", octal, hexadecimal);

Integer Type

// "short int" or short
short int a_1;
// or
short a_2;

// "long int" or "long"
long int b_1;
// or 
long b_2

// "long long int" or "long long", at least 64-bit cpu.
long long int c_1;
// or
long long c_2;

integer type

The "int32_t" is equal to "int".
The "uintmax_t" is bigger than "long long int" and "unsigned long".

Floating-Point numbers

float, double, long double.

floating-point

printf("%f\n", -1.32e-11); 

Boolean Type

// example
_Bool b_1;

// C99, stdbool.h
bool b_2;

sizeof

sizeof 搭配 %zd

macro

#define MAX(a,b) ((a) > (b) ? (a) : (b)) 
#define SWAP(a, b, tmp) ((tmp) = (a), (a) = (b), (b) = (a))
#ifndef SOME_H
#define SOME_H

/* Declare some data types and public functions. */

#endif
// 測測編譯環境
#if defined(_WIN32)
	#define PLATFORM "windows"
#elif defined(__linux__)
	#define PLATFORM "Linux"
#elif defined(__APPLE__)
	#define PLATFORM "mac"
#else
	#define PLATFORM "other os"
#endif

一個#代表字串

#的內容要左右括號。(變數為字串)
#include <stdio.h>
 
#define pow(a) (#a)

int main(int argc, char *argv[]) {
	printf("%s\n", pow(sdkfjsdkf));
} 

...和__VA_ARGS__

#define test(...) (printf("%d\n", __VA_ARGS__))

...

test(5000);
// output: 5000

##可黏兩個變數

#define test(a,b) (printf("%d\n", a##b))

...

test(50,6);
// output: 506

換行(反斜線)

#define test(5,6) ( \
printf("%d\n", a##b))

function sample

#define cmp(a,b,tmp)({ \
if((a)>(b)) { \
tmp = -1; \
} else if(((a)<(b))) { \
tmp = 1; \
} \
else { \
tmp = 0; \
} \
}) 

pragma

說明define時的變數名稱可能撞名,可以在header的第一行加入#pragma once
#pragma once
#ifndef UTILS_H 
#define UTILS_H

/* ... */

#endif
參考 更多巨集

assert

assert內容是True則不做任何事, Flase為顯示stderr,並停止。
#include <assert.h>

/* ...  */

int a;
scanf("%d", &a);
assert(a>10);
printf("a == %d", a);

scanf

Pass parameter into the "*".
*.*的第一個*是整個寬度(包含小數點位數), 第二個*為小數點後幾位。
int width, percision;
scanf("%d, %d", &width, &percision);
printf("%*.*f", width, percision, 3.2)

處理scanf("%d", var), var為非整數

int status;
int code;
while(status=scanf("%d", code)){
	if(status != 1)
		scanf("%*s"); // dispose non-integer
	printf("Enter an integer, please.\n");
}

static

ShengYu Talk - C/C++ static 的 5 種用法

while搭配scanf輸入資料

#include <stdio.h>
#define FREEZING 4.0

int main(int argc, char *argv[]) {
	float temperature;
	int all_day = 0;
	int cold_day = 0;
	printf("Input temperature value. (any character to quit)\n");
	while(scanf("%f", &temperature)) {
		all_day++;
		if(temperature < FREEZING)
			cold_day++;
	}
	if(all_day==0)
		printf("No data!\n");
	else
		printf("%d cold day. Total of %d day(s).\n", cold_day, all_day);

	return 0;
}

getchar() and putchar()

加密輸入值
#include <stdio.h>

int main(int argc, char *argv[]) {
	char ch;
	/* move characters. */
	/* getchar() be a statement. */
	/* while( (ch=getchar() ) != '\n'), don't need "ch = getchar()" in end. */
	/* The operator '!=' is higher priority than '='. Therefore, It need to bracket on "ch = getchar()". */
	ch = getchar();
	while(ch != '\n') {
		if(ch == ' ') {
			putchar(ch);
		} else {
			putchar(ch+1); // encryption
		}
		ch = getchar();
	}
	putchar(ch); // print the newline.
	return 0;
}

ctype.h

提供判斷char類型的函數(ex. isalpha())
改寫上題
#include <stdio.h>
#include <ctype.h>

int main(int argc, char *argv[]) {
	char ch;
	/* move characters. */
	while( (ch=getchar()) != '\n') {
		if(ch == isalpha()) {
			putchar(ch+1); // encryption
		} else {
			putchar(ch);
		}
	}
	putchar(ch); // print the newline.
	return 0;
}
cplusplus - cctype

conio.h

unbuffered input with getche().

EOF

Control + Z
while( (ch=getchar()) != EOF); 

Pass pointer to function

ex. sum
#include <stdio.h>
#define SIZE 10
int total(int *start, int *end)
{
	int sum = 0;
	while(start < end) {
		sum += *start;
		start++;
	}
	return sum;
}
int main(int argc, char *argv[]) {
	int a[SIZE];
	int sum;
	for(int i=0; i<SIZE; i++)
		a[i] = 10;
	sum = total(a, a+SIZE);
	printf("%d\n", sum);
	return 0;
}



pointer and array

*(array_a + 2) == array_a[2];
*(*(array_b + 4) + 5) == array_b[4][5];


int a[3][2] = {{1,2}, {3,4}, {5,6}};
	int (*p)[2]; // The 'p' is an address that point to two ints' address.
	/* Alternatively, p[][2] */
	p = a+1;
	printf("%d\n", (*p)[1]);
	/* output: 4 */

Variable-Length Arrays (VLAs)

#define COLS 4
int Sum(int ar[][COLS], int rows)
{
	int total = 0;

	for(int r=0; r<rows; r++)
		for(int c=0; c<COLS; c++)
			total += ar[r][c];

	return total;
}
假設要傳2維array, 其rows和columns也是傳送參數,則rows和columns要先傳(寫在左邊)
int Sum(int rows, int cols, int ar[rows][cols]); 
C99/C11 可以捨棄變數名稱
int Sum(int, int, int ar[*][*]); 

Compound Literals

int div[2] = {10, 20};
/* equal */
/* nameless */
(int [2]){10,20};

/* initialize */
(int []){50, 20, 100}; // a compound literal with 3 elements.

/* example */
int *pt1;
pt1 = (int [2]) {10, 20};


/* example */
/* pass parameters */
int sum(const int1r[], int n);

...

int total;
total = sum((int []{4, 2, 2, 4, 5}, 6);


/* example */
int (*pt)[4]; // int pt[][4] can not initialize.

pt = (int [2][4]){ {1,2,3,4}, {5,6,7,8} };

Strings


puts(); 

char str[] = "First" " Second" 
	" Third.";
/* Output: First Second Third.*/


fgets()
fputs()

putchar with pointer

#include <stdio.h>
void put1(const char *str)
{
	while(*str!='\0') // while(*str)
		putchar(*str++);
}
int main(int argc, char *argv[]) {
	put1("I want to fly!\n");
	return 0;

}



sprintf

write data into an address.
#include <stdio.h>
int main(int argc, char *argv[]) {
	char a1[40];
	int count;
	count = sprintf(a1, "Number is %d.", 10);
	puts(a1);
	printf("%d\n", count);
	return 0;

}



malloc

double *pt
pt = (double *) malloc(30 * sizeof(double));

...

free(pt);

Volatile

只某個變數的值會隨時變化,如果沒有告訴compiler這個性質,它可能會最佳化結果(參考有詳細說明),導致錯誤。
reference - w3help

restrict

用來修飾pointer, 告訴compiler不能用其他變數去改這pointer的data。
int *restruct pt = (int*) malloc(10 sizeof(int));
Y CP的部落格

_Atomic

即設置的變數不能中途被訪問。 CSDN - C语言的_Atomic类型限定符(C11)

Files I/O


fopen

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

int main(int argc, char *argv[]) {
	int ch;
	FILE *fp;
	fp = fopen("SomeTextFile.txt", "r");
	while((ch=getc(fp)) != EOF)
		putc(ch, stdout); // putchar
	fclose(fp);

	return 0;
}


getc()

fp為FILE類型的指標, 功能是取得內容。
getc(fp); 

putc()

ch為要寫進的內容, fp為FILE類型的指標。
putc(ch, fp); 

rewind()

Go back to begining of file.
rewind(fp); 

fscanf()

參數: 第一個為file的指標, 第二個為類型, 第三個為所要放進內容的地方(要接受內容的變數)
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
	int ch;
	char word[50];
	FILE *fp;
	fp = fopen("SomeTextFile.txt", "r");
	while(fscanf(fp, "%s", word)==1);
	fclose(fp);
	printf("%s", word);



	return 0;
}



fgets()

限制從file取得的長度
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
	int ch;
	char word[50];
	FILE *fp;
	fp = fopen("SomeTextFile.txt", "r");
	fgets(word, 7, fp);
	fclose(fp);
	printf("%s", word);

	return 0;
}


fputs()

參數: 第一個為char的array指標變數, 第二個為FILE類型的指標。
fputs(word, fp); 

Pointers to Strutures

#include <stdio.h>
 
struct book {
	char linear_algebra[50];
	char Discrete[50];
};

int main(int argc, char *argv[]) {
	struct book bookcase[2] = {
		{"book_a", "book_b"},
		{"book_c", "book_d"}
	};
	struct book *pt;

	pt = bookcase;

	puts(pt->linear_algebra);
	// output: book_a
	
	pt++; // point to next index.
	puts(pt->linear_algebra);
	// output: book_c

	return 0;
}


fwrite()

參數: 第一個為字串的指標, 第二個為寫入類型大小, 第三個為要寫入多少進去, 第四個為寫進FILE類型的指標。
fwrite(&primer, sizeof(struct book), 1, fp); 
ref - 程式人生
ref - C語言中文網

enum

enum DAY {
	MON=1,
	TUE,
	WED,
	THU,
	FRI,
	SAT,
	SUN
};
int main(void)
{
	enum DAY day_var;
	day_var = WED;

	printf("%d\n", day_var);
	// output: 3


	return 0;
}
ref - runoob

calloc

需要stdlib.h
calloc和malloc相似,但calloc會初始化內容為都為0。calloc輸入為2個參數。

realloc

重新分配大小

int *returnArr = (int *)malloc(100*sizeof(int));
int *size = 10;
returnArr = realloc(returnArr, (*size)*sizeof(int));


Hash Table

int t['z'+1] = {
	['a'] = 10,
	['c'] = 30,
	['d'] = 40,
};
printf("%d\n", t['f']); // t['f'] == 0
printf("%d\n", t['d']); // t['d'] == 40
cucerdariancatalin - [1LINER][Fastest Solution Explained] O(n)time complexity O(n)space complexity

Print binary bit


int a= 10
for(int n=31; n>=0; n--) {
	printf("%d", a>>n & 1);
}

Bit Mask




int n = 10;
// set the 5th bit from right to 1
int mask = 1<<4;
n |= mask;

// set the 3rd bit from right to 0
int mask = ~(1<<2);
n &= mask;

// toggle the 4rd bit from right
int mask = 1<<3;
n ^= mask;

conio.h

get char without display
getch() 
display version
getche() 

set cursor position

    // COORD pos = { 10,5 };
    COORD pos;
    pos.X = (short)5;
    pos.Y = (short)3;
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
 
    SetConsoleCursorPosition(hOut, pos);
 
 	/* set text color */
    SetConsoleTextAttribute(hOut, 0x01 | 0x05);
 
    printf("Something Something");

typedef

reference

function pointer

reference
reference2

Pointer

pointer

讀取的資料是由多個register內容組合出來


UINT32 EXA;
UINT32 EXB;
UINT32 EXC;
UINT32 EXD;

CHAR8 ID[(32/8)*4+1] = {0};

*(UINT32 *)ID = EXA;
*(UINT32 *)ID = EXB;
*(UINT32 *)ID = EXC;
*(UINT32 *)ID = EXD;

printf("%s\n", ID); // 前提是整個字串要是滿的