浮點數:
x = Mx*2^Ex為一個規格化浮點數,Mx為x的尾數,Ex為x的階碼。
1e-6:表示1 * 10 ^ (-6)。
編譯時執行:
sizeof是運算符(而非函數),在編譯時執行,不會導致額外的運行時間開銷。
三元運算符:是右結合運算。
數據類型:
char:占1個字節 short:占2個字節 int:占4個字節 float:占4個字節 double:占8個字節 一個變量本身定義為常量const時,必須初始化 常量指針:不能通過常量指針修改其指向的值(只是從p的角度來看)。 const int *p; int const *p; 指針常量:指針其本身就是常量(故定義時須初始化),而且也不能通過這個指針修改其指向: int * const p = &a; 數組指針(指向一維數組的指針 / 行指針):char (*p)[10] —— 打括號就是說,先看括號里面的。故可以這樣理解: 舉例, 二維數組char a[10][10], char (*p)[10];p = a。 首先確定,char (*p)[10]只是將p定義為一個指針(其作用是指向某個數組整體,而不是這個數組中的某個元素);10就是指定了指向的數組的長度 p = a就讓p指向了a[0]這個數組;於是p++,就讓p指向了下一個數組a[1]; 所以若p = a,那么*p就是獲得a[0]這個數組。 既然char (*p)[10]是指向數組的指針,那么通用的使用就是:把數組的地址給p,即char (*p)[10];char s[]="abcd";p=&s; 而二維數組a[][]的數組名a的含義是:a == &a[0]; 指針數組(數組元素是數組):char *p[10] —— 沒有括號,所以可以這樣看:這是一個數組,其元素類型是char *p。這里是一個放了10個指針的數組。所以p[0]=arrary;是指向數組首元素,而不是整個數組
標准輸入輸出格式:
當數據的實際位寬大於printf中的指定位寬時,將按照數據的實際位寬輸出數據。
//輸出 printf("%ld\n", test); /* 以長整型格式輸出 */ printf("%f\n", test); //輸出單雙精度浮點數 printf("%4.2f\n", test); //輸出數據共占4位(包括小數點),有2位小數;其他數據類型也是如此(自然有些是沒有小數的) printf("%u", n); //n是unsigned int printf("%s\n", str); //輸出一個字符串 printf("%p\n, p); //輸出地址 //輸入 /*scanf:返回值為成功接收到的、輸入的變量值個數。 如scanf("%d%d%d",i,j,k,a,b)則只能返回3(因為只能接收三個)*/ char *str = (char *)malloc(N * sizeof(char)); scanf("%s", str); //輸入一個字符串 scanf("%lf", &test); //輸入雙精度浮點數 scanf("%d,%d", &a, &b); //輸入必須與指定的格式相同。比如這里有",",那么在Console中輸入也需要","
隨機數:
//#include <stdlib.h>:rand、srand //#include <time.h>:time srand(0); printf("%d\n", rand()); //rand對應於srand,只要srand的種子不變,rand的隨機值也不會變;rand的范圍是0 - int srand(time(NULL)); //srand(unsigned) printf("%d\n", rand()); //time函數返回當前時間(秒);參數param如果不為BULL,則time會將時間賦給param。故這樣一來隨機數就會一直改變(真正實現隨機) printf("%d\n", rand() % 100 + 1); //生成1-100的隨機數:rand() % 100是0-99
指數函數:
pow(x, y) //表示x的y次方 —— math.h
數組:
初始化:
int count[10] = {0}; //長度為10的數組,全都初始化為0;定義數組時,數組長度只能是常量,不能是變量或含變量的表達式
二維數組:
多維數組在內存中實際上都是一維存儲的。例如二維數組,我們只是在邏輯上可以理解為二維的矩陣,但實際上二維數組是一維數組,每個元素還是一維數組,所以整個二維數組都是"一條線"
1、因此int a[3][3]={1...9};int (*p)[3] = a;此時不僅可以*(*p+2),還可以*(*p+8)=*(*(p+2)+2),只要不越二維數組的界(這里是9);
簡單點就是:int a[3][3] = {1...9};int *p = &a[0][0];此時可以從頭指到尾:頭是*p,尾是*(p+8);
2、所以二維數組a有m行n列,則在a[i][j]之前的元素個數為i * n + j —— 因為a[i][j]是第i + 1行,第j + 1列,而前i行都是在a[i][j]之前的
求數組大小:
char s[][20] = { "first", "second", "Third" }; char (*p)[20] = s; printf("%d %d\n", sizeof(s) / 20, sizeof(p)); //3、4:因為p要找"\0",即'\0' —— {"...", "...", "...", "\0"} //用指針數組 char *p[] = {"How", "are", "you"}; printf("%d\n", sizeof(p) / sizeof(char *));
函數:
函數返回值:
printf("%d\n", func(-1)); //main函數 int func(int i) { if (i == 0) { return i; } else { printf("h\n"); //這種情況,會返回printf輸出的字符個數(包括轉義符):此時return 2 } }
數組作為函數參數,形參數組與實參數組實際上是同一個數組,即傳址調用;數組作為實參,只需要寫數組名(無論是幾維數組)。
變量的生命周期與作用域:
#include <stdio.h> void Incre(); int main() { Incre(); Incre(); return 0; } void Incre() { static int x = 1; //靜態:第二次就輸出上次,保存的x的值;此外這還是一個局部var,因此作用域還是Incre printf("%d\n", ++x); }
字符串:
字符常量與字符串常量的區別:
- 字符串常量:1、字符串里面包含的字符是連續存儲的。2、每個字符串都有結束標記("\0"),這是一個特殊的字符,即ASCII碼為0的字符。3、C語言用字符數組(沒有字符串變量)來動態存儲字符串,例如char s[10] = {'a', 'b', '\0'}是一個字符串,而char s[10] = {'a', 'b'}不是。或者寫為char s[] = "abc"(在初始化的情況下可以省略數組大小)。存儲多個字符串(用二維數組):char s[][10] = {"星期一", "星期二"}(第一個大小可省略,由字符串的個數,即二維數組中包含數組的個數決定)。
- 字符常量:char s = 'a'。
用指針來訪問字符串:
#include <stdio.h> int main() { char *p = NULL; char s[] = "abc"; p = s; //反過來就不行了,因為數組名相當於是一個指針常量 printf("%c\n", *p); //現在只是指向字符串的第一個字符 //printf("%s\n", *p); //這樣是不行的,應該是printf("%s\n", p);輸出的是這個指針指向字符串的某個字符以及后面剩下的字符,所以p在此時可以用s替代 return 0; }
輸入輸出字符串:
char s[] = "adjshd"; char s1[] = "casn";char *p = s; char *p1 = s1; gets(p); //可以輸入空格 puts(p); scanf("%s", p1); printf("%s\n", p1);
但是gets是存在安全隱患的(它沒有限制輸入的大小,即輸入可能超出字符數組的大小,此時就可能把輸入存到了指定的字符數組之外的地方):
char s2[] = "sdfjhasjd"; char *p2 = s2; char n = 3; //fgets限制輸入的長度 fgets(p2, n, stdin); //最多只能接收n - 1個字符 puts(p2);
getchar函數:
用處1:
#include <stdio.h> #include <math.h> int main() { int n = 0; char c = 'c'; int result = scanf("%d", &n); if(result != 1) //輸入與scanf指定的類型不符,則不能接收到。未能成功接收的字符會暫時放在緩沖區 { c = getchar(); //此時getchar就是將緩沖區的字符一次取走一個,並返回 } printf("%d %c\n", n, c); return 0; }
用處2:
#include <stdio.h> #include <math.h> int main() { char c = 'c'; //getchar直接從stdin讀取一個字符,putchar從stdout輸出 c = getchar(); putchar(c); return 0; }
字符串處理函數:
//需要#include <string.h> -- 字符串處理函數strcmp、strlen、strcpy、strcat strcmp(s1, s2); //兩個字符串自左向右,逐個字符相比(比較ASCII碼),直到出現不同字符或'\0'為止,此時若:s1==s2;return 0;s1 > s2;return 1;否則return -1. strlen(s1); //返回字符串s1的長度,例如:char s1[10] = "abcde";printf("返回字符串的長度:%d,返回數組的長度%d\n", strlen(s), sizeof(s)); char source[] = "hello kit";char destination[] = "world"; puts(strcpy(destination, source));puts(destination);//source->destinations char source[] = "hello kit";char destination[] = "world"; puts(strcat(destination, source));puts(destination);//即destination + source
函數庫:
字符處理函數#include <ctype.h>: 函數的參數皆為int,返回也為int int isdigit(int c); //判斷是否為數字字符,例如:如果是'3',return 1;是'a',return 0; int toupper(int c); 實用函數#include <stdlib.h> double atoi(const char *s);
double atof(const char *s); //例如: //printf("%6.2f\n", atof("1e2"));輸出:100.00——還要算上小數點 //printf("%6.2f\n", atof("y3")); 輸出: 0.00;就算是e3也不會當成是科學計數,而是和y3一樣
枚舉類型:
#include <stdio.h> int main() { //定義枚舉類型,集合{}中的元素,是枚舉元素 —— 供枚舉變量進行選擇 //枚舉元素的值:如果沒有指定具體值,編譯器會把第一個元素處理成0,后面元素以此+1:因此枚舉元素是常量 //當然也可以自定義枚舉元素的值:例如指定Tuesday = 100,那么Wednesday也遵循+1的原則,因此Wednesday = 101 enum Date { Monday, Tuesday, Wednesday }; //定義枚舉變量 //1、直接在定義類型時,順便把變量定義了 //enum Date { Monday, Tuesday, Wednesday } date; //2、或者只定義變量 //enum { Monday, Tuesday, Wednesday } date; //枚舉變量選擇具體的枚舉值 enum Date date = Tuesday; date = Wednesday; printf("%d\n", date); return 0; }
聯合union:
編譯器處理union時,一個union所有成員共用同一段內存空間(同一時刻,只有一個成員使用內存空間,存放成員值),因此內存空間的大小=最長的成員大小。具體使用如下:
#include <stdio.h> int main() { union { int i[2]; int k; int c; } t, *s = &t; //給哪個成員賦值,內存空間就被這個成員使用 s->i[0] = 10; s->i[1] = 20; printf("%d\n", s->c); s->k=30; printf("%d\n", s->c); s->c = 1000; printf("%d\n", s->c); printf("%d\n", s->i[1]);//始終為20 return 0; }
使用聯合的一些注意事項:
1、聯合不能作為函數參數傳遞。2、不能整體初始化或者整體賦值,只能對其成員一個一個賦值。3、不能作為函數返回值。
結構體:
#include <stdio.h> typedef struct student { int number; char name[20]; char sex; } S;//此時S是別名 struct { int year; int month; int day; } birth;//此時birth是結構體變量 int main() { S s; s.number = 1000; birth.year = 250; printf("%d %d\n", birth.year, s.number); return 0; }
文件操作:
<stdio.h>中的一些變量類型、宏定義:
- 文件結束符:#define EOF (-1)
- 存儲文件流信息的類型:typedef struct _iobuf FILE;
- 類型的大小,即sizeof運算符的結果:typedef unsigned int size_t;
打開已存在文件、或新建一個文件:
函數原型:FILE *fopen(const char *filename, const char *mode);//用FILE的指針變量操縱文件 根據打開模式(mode)的不同決定:新建或打開文件 1、文本文件: mode的值:r(打開已有文件,只讀)、w(打開文件,只寫、覆蓋寫入,即打開后刪除原有內容,重新寫入。若文件不存在,則新建)、a(打開文件,只寫、追加寫入。若文件不存在,則新建) 可讀寫:r+(打開已有文件,覆蓋寫入)、w+(新建文件)、a+(打開文件。若文件不存在,則新建。寫:追加寫入) 2、二進制文件mode:形如ab、ab+
=>每次讀寫都會從文件游標開始讀(第一次讀,游標在文件開頭),游標屬於fp指向的 FILE 變量:因此,對於同一個FILE變量,fgetc的調用也會影響到fgets的讀取位置
清空緩沖區數據,並關閉文件:
函數原型:int fclose(FILE *fp); 成功關閉,釋放掉文件占用的內存,return 0;發生錯誤,return EOF(常量,在stdio.h中定義);
寫入文件:
寫入一個字符:int fputc(int c, FILE *fp); 如果成功,return 剛寫入的c;如果失敗,return EOF; 寫入一個字符串:int fputs(const char *s, FILE *fp); 如果成功,return 一個非負值;失敗,return EOF;
格式化寫入文件:
//與fputs同理,函數原型:int fprintf(FILE *fp, const char *formatSting, ...); //像printf一樣,接受可變長參數,如: fprintf(fp, "%d != %d\n", 1, 2);//即寫入1 != 2
讀取文件:
//與寫入同理:int fgetc(FILE *fp) printf("%c\n", fgetc(fp)); fgetc(fp);//每調用一次,讀取文件的游標,就會向后移動一個char printf("%c\n", fgetc(fp)); //讀取字符串:char *fgets(char *buf, int n, FILE *fp); //讀取n - 1個字符。並將讀取到的字符串,復制到字符串變量buf中,最后以\0結束 —— buf的長度應不少於n //返回的字符串與buf的值相等 char str[7]; char *buf = str; printf("%s\n", fgets(buf, 7, fp));//如果還未讀取n個char,就遇到了\n或者EOF,則直接結束本次讀取(包含\n)
直接讀取一個單詞(從游標開始,到遇到的第一個空格為止,認為是一個單詞;游標是讀到了這個空格的,因此調用下面的函數后,游標指向這個空格之后):
char buff[255]; //與fprintf不同:%s作為sourceString(不加修飾),buff作為destString fscanf(fp, "%s", buff); fscanf(fp, "%s", buff); printf("%s\n", buff);//讀到第二個單詞
檢測當前游標是否指向文件結尾(EOF):
int feof(FILE *fp);//文件結束,return 1;否則return 0;