最近,一邊在改paper,一邊快速的翻看了一下《C程序設計語言》,記錄了一下讀書的筆記,文末附有其他人的讀書筆記,對比起來,相差甚遠,慚愧!
第一章
字符輸入/輸出
getchar();//通常通過鍵盤輸入
putchar();
'c'和"c"不同,后者多個'\0'
在復制文件內容時,可以使用getchar();
#include <stdio.h>
/* 將輸入復制到數出 */
main()
{
int c;
while ((c = getchar()) != EOF) //學這種寫法,在Linux那本書很多這種寫法
putchar(c);
}
書里面有一句:在C語言,所有函數參數都是“通過值”傳遞的。
第二章
extern聲明:單獨放在一個頭文件聲明。
分清楚"定義"和"聲明"
枚舉常量
enum boolean {NO, YES};
任何變量的聲明都可以使用const限定符限定,該指定的變量的值不能修改。
.c文件 -- 編譯 --> .o文件 -- 加載(鏈接)--> a.out
cc main.c getline.c strindex.c
//編譯這3個文件,并把生成的目標代碼分別存放在文件main.o getline.o strindex.o中,然后再把這3個文件一起加載到可執行文件a.out
cc main.c getline.o strindex.o
//對main.c進行修改后,可對main.c重新編譯,和之前兩個.o文件一起加載到可執行文件
逆波蘭表示法:用棧來實現
第四章
外部變量
構成C語言程序的函數與外部變量可以分開進行編譯。一個程序可以存放在幾個文件中,原先已編譯的函數可以從庫中進行加載。注意幾個問題:
- 如何進行聲明才能確保變量在編譯時被正確聲明?
- 如何安排聲明的位置才能確保程序在加載時各部分能正確連接?
- 如何組織程序中的聲明才能確保只有一份副本?
- 如何初始化外部變量?
如果要在外部變量定義之前使用該變量,或者外部變量的定義與變量的使用不在同一個源文件中,則必須在相應的變量聲明中強制性地使用關鍵字extern
在一個源程序的所有源文件中,一個外部變量只能在某個文件中定義一次,而其他文件可以通過extern聲明來訪問它(定義外部變量的源文件中也可以包含對給外部變量的extern聲明)
Ex1:
//file1
extern int sp;
extern double val[];
...
//file2
int sp = 0;
double val[MAXVAL];
Ex2:
//file1
extern int sp;
extern double val[];
...
int sp = 0;
double val[MAXVAL];
靜態變量
用static聲明限定外部變量與函數,可以將其后聲明的對象的作用域限定為被編譯源文件的剩余部分。
static的作用??
寄存器變量
register聲明告訴編譯器,它所聲明的變量在程序中使用頻率較高。其思想是,將register變量放在機器的寄存器中,這樣可以使程序更小,執行速度更快。
遞歸
遞歸實現快速排序
C預處理器
- 文件包含
#include "文件名"
#include <文件名>
- 宏定義 (注意宏定義的使用,例如要記得加括號)
#define 名字 替換文本
//替換文本是任意的,如下:
#define MAXVAL 100
#define forever for(;;) /*無限循環*/
#define MAX(A,B) ((A) > (B) ? (A) : (B)) /*看著像函數,實際只是起文本替換作用*/
- 注意
#undef getchar //取消getchar宏定義
//為了保證hdr.h文件的內容只被包含一次
#if !define(HDR) or #ifndef HDR
#define HDR
/* hdr.h文件的內容放在這里 */
#endif
//先測試系統是哪個版本的,引入對應的頭文件
#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
第五章
- 指針與函數參數
由于C語言是以傳值的方式將參數值傳遞給被調用函數,因此,被調用函數不能直接修改主調函數中變量的值。
void swap(int x, int y){
int temp;
temp = x;
x = y;
y = temp;
}
int mian(){
int a = 10, b = 20;
swap(a, b);//無法實現交換,該函數僅僅交換了a和b的副本的值
}
那應該怎么辦呢?傳值變成傳指針!!!
void swap(int *x, int *y){ /* 交換*x和*y */
int temp;
temp = *x;
*x = *y;
*y = temp;
}
int mian(){
int a = 10, b = 20;
swap(&a, &b);//傳指針,指針參數使得被調用函數swap能夠訪問和修改主調函數main中對象的值
}
- 指針與數組
//在函數定義中,形式參數
char s[];和char *s;是等價的 //char *s; 是字符指針
- 指針數組以及指向指針的指針
void qsort(char *v[], int left, int right){
int i, last;
void swap(char *v[], int i, int j);
if (left >= right)
return;
swap(v, left, (left + right)/2);
last = left;
for (i = left+1; i <= right; i++)
if (strcmp(v[i], v[left]) < 0)
swap(v, ++last, i);
swap(v, left, last);
qsort(v, left, last-1);
qsort(v, last+1, right);
}
void swap(char *v[], int i, int j){
char *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
- 命令行參數
int main(int argc, char *argv[]) {} //字符指針數組,數組元素是字符指針
- 指向函數的指針
void qsort(void *lineptr[], int left, int right, int (*comp)(void *, void *));
int (*comp)(void *, void *) //表明comp是一個指向函數的指針,該函數具有兩個void*類型的參數,其返回值類型為int。
C++的qsort:qsort函數定義在頭文件<algorithm>中
void qsort (void* base, size_t num, size_t size,
int (*compar)(const void*,const void*));
int compar (const void* p1, const void* p2);
//example
/* qsort example */
#include <stdio.h> /* printf */
#include <stdlib.h> /* qsort */
int values[] = { 40, 10, 100, 90, 20, 25 };
int compare (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int main ()
{
int n;
qsort (values, 6, sizeof(int), compare);
for (n=0; n<6; n++)
printf ("%d ",values[n]);
return 0;
}
第六章
- 結構基本知識
結構是一個或多個變量的集合,這些變量可能為不同的類型。
struct point {
int x;
int y;
};
struct {...} x, y, z; //struct聲明定義了一種數據類型,在標志結構成員表結束的右括號之后可以跟一個變量表,這與其他基本類型的變量聲明是相同的。
int x, y, z; //本質是一樣的。
struct point pt;
struct point maxpt = {320, 200};
printf("%d,%d", pt.x, pt.y);
struct rect {
struct point pt1;
struct point pt2;
};
struct rect scream;
scream.px1.x;
- 結構與函數
struct point makepoint(int x, int y){ //參數名和結構成員同名不會引起沖突
struct point temp;
temp.x = x;
temp.y = y;
return temp;
}
- 結構指針
struct point *pp; //定義pp為一個指向struct point類型對象的指針
如果pp指向一個point結構,那么*pp即為該結構,而(*pp).x和(*pp).y則是結構成員
struct point origin, *pp;
pp = &origin;
printf("%d,%d",(*pp).x, (*pp).y);
//p->結構成員(->指針使用)
printf("%d,%d",pp->x, pp->y);
struct rect r, *rp = &r;
//以下四個等價
r.pt1.x;
rp->pt1.x;
(r.pt1).x;
(rp->pt1).x;
- 結構數組
struct point {
int x;
int y;
} points[10];
struct point points[10];
sizeof(對象) sizeof(類型名) 返回一個整型值(size_t),等于指定對象和類型占用的存儲空間字節數
- 自引用結構
常用于樹結構
- 表查找
哈希表
- typedef
typedef int Length;
Length len, maxlen;
Length *lengths[];
typedef char *String;//將String定義為char*字符指針
String p;
- 聯合
和訪問結構的方式一樣,是一種“特殊的”結構
第七章&第八章
第七章講輸入/輸出標準庫,第八章講Unix系統的接口,文件操作,與《UNIX環境高級編程》一書某些章節一樣,在看這本書時再展開。
最后,分享幾個別人的讀書筆記
https://www.cnblogs.com/xkfz007/archive/2012/08/05/2623702.html
https://www.cnblogs.com/xkfz007/articles/2566424.html
https://github.com/1326670425/TCPL
http://kissg.me/2016/07/10/notes-on-the-c-programming-language/