1. 程式人生 > >C程式設計語言(第二版)-讀書筆記

C程式設計語言(第二版)-讀書筆記

The C Programming Language

1. 設計一個程式,作用為無限字元輸出:

int c;

printf(“Please in put the char …\n”);

//getchar接受字元輸入並存放到緩衝區,逐個返回給c

c=getchar();

while(c!=EOF)

{

putchar(c);

c=getchar();

}

2. 設計一個程式,統計字元數目:

printf(“Please input char …/n”);

long nc=0;

while(getchar()!=EOF)

{

++nc;

}

printf(“%d\n”,nc);

3. 設計一個程式,統計單詞的個數:

#define IN 1

#define OUT 2

//c表示charnc表示出現字元的數目,nw表示單詞數目,nl表示段落數

int c, nc, nw, nl, state;

state = OUT;

nl = nw = nc =0;

while(c=getchar()!=EOF)

{

++nc;

if(c==’\n’)

{

    ++nl;

}

if(c==’ ’||c==’\n’||c==’\t’)

{

    state=OUT;

}

else if(state==OUT)

{

    state = IN;

    ++nw;

}

printf(“字元數:%d,單詞數:%d,

段落數:%d”,nc,nw,nl);

}

4. C語言中的資料型別:

|-char1byte)、int4byte)、float4byte)、double8byte)、bool(1byte)

|-整形兩種限定符:

|-shortlong,用於限定整形intint可以不寫。short int2byte)、long int4byte)。

|-unsignedsigned用於限定是否含有符號,可用於charint。預設為signed

5. 判斷閏年:

int year=0;

scanf(“%d”,&year);

if(((year%4==0)&&(year%100)!=0)||year%400==0)

{

    printf(“This year %d is leap year”,year);

}

else

{

    …

}

6. enum#define定義常量的對比

|-enum定義列舉,#define定義巨集,enum定義常量的值可以自動生成。

|-enum能夠用於除錯,而define定義的常量編譯時不檢查,只是對其進行字元的替換。

7. 常用函式自定義實現:

//strlen

int strlen(char s[])

{

int i=0;

while(s[i]!=’\0’)

{

    ++i;

}

return i;

}

//或者

int strlen(char *s)

{

int n;

for(n=0;*s!=’\0’;s++)

{

    n++;

}

return n;

}

//atoi

int atoi(char s[])

{

int n=0;

for(int i=0;s[i]>=’0’&&s[i]<=’9’;++i)

{

    n=(s[i]-‘0’)+10*n;

}

}

//lower

int lower(int c)

{

if(c>=’A’&&c<=’Z’)

{

    return c+(‘a’-‘A’)

}

else

    return c;

}

//strcat

void strcat(char s[], char t[])

{

int i=0;

int j=0;

while(s[i]!='\0')

{

++i;

}

while ((s[i++]=t[j++])!='\0')

{

}

}

//刪除字元

void squeeze(char s[], int c)

{

    int j,j;

for(int i=j=0;s[i]!=’\0’;i++)

{

    if(s[i]!=c)

    {

        s[j++]=s[i];

}

s[j]=’\0’;

}

}

//trim,簡化版,用於刪除字串尾部空格,理解break的使用

int trim(char s[])

{

int n;

for(n=strlen(s)-1;n>=0;n--)\

{

    if(s[n]!=’ ’&&s[n]!=’\t’&&s[n]!=’\n’)

    {

    break;

}

s[n+1]=’\0’;

return n;

}

}

//strcpy

void strcpy(char *s,char *t)

{

while((*s++==*t++)!=’\0’)

{}

}

//strcmp

int strcmp()

{

for(;*s==*t;s++,t++)

{

    if(*s==’\0’)

    {

        return 0;

}

return *s - *t);

}

}

8. 在進行復制和函式引數傳遞時,低精度的可以向高精度的進行自動轉換。例如接受float引數的函式樂意接受doulbe型別的引數。高精度要轉換成低精度就要進行強制型別轉換。

9. c語言中,字元陣列和字串很容易引起混淆。c語言中的字串被當做成字元陣列來處理。字串的定義有兩種:

char * c = “Hello”;或者char s[] =“hello”;字串在字元陣列的結尾加上’\0’,因此對於char s2[] = {‘h’,’e’,’l’,’l’,’o’};sizeof(s2)=5,而sizeof(s)=6

10. 演算法:

//冒泡

void bubble(int s[],int n)

{

int tmp=0;

for(int i=0;i<n;i++)

{

for (int j=0;j<n-i;j++)

{

if (s[j]>s[j+1])

{

tmp = s[j];

s[j] = s[j+1];

s[j+1] = tmp;

}

}

}

}

//折半查詢,x是要查詢的數字,v是已排序的陣列,n是陣列長度

int binsearch(int x,int v[],int n)

{

int low,high,mid;

low = 0;

high = n-1;

while (low<=high)

{

mid = (low + high)/2;

if(x<v[mid])

{

high = mid-1;

}

else if(x>v[mid])

{

low = mid +1;

}

else

return mid;

}

}

10. 對於extern修飾符,extern i;表示變數宣告,並未生成物件,用於說明i為全域性變數,可在不同的檔案中呼叫。

11. 對於static修飾符,在c語言中,使用static宣告變數為檔案中訪問,檔案外不能訪問該static變數。

12. 暫存器變數使用register表示,其訪問速度快,但暫存器地址不能訪問。

13. 前處理器:

|-#include<>系統預設搜尋路徑,””原始檔路徑+預設路徑

|-#define:編譯時進行字元替換

|-優點:節省呼叫開銷

|-缺點:重複計算產生副作用

|-#ifndef…#define…#endif:條件包含

14. 關於*++(--)的結合性,先++*

|-*p++ ==> p++; *p;

|-(*p)++ ==> p指向的物件值+1;

例如int s[]={2,3};int *p = s;printf(“%d,”*p++);結果輸出的是2,而不是3,因為是先引用在++

15. ++ii++:在VC編譯環境下,如果在一個計算表示式中,首先計算++i,然後看有幾個i++,完成該表示式後,有幾個i++i就自增幾。例如:int i=3,j; j=(i++) + (i++) + (++i);printf(“i=%d,j=%d”,i,j);編譯輸出為612

16. VC的編譯器中,printf函式是自右向左執行的。例如,printf(“%d,%d”,i,i+1);首先計算i+1,然後再輸出i

17. 使用巨集編寫比較兩個數的大小

#define max(A,B) ((A)>(B)?(A) : (B))

注意一定要加括號,用於放回巨集的副作用。

18. 對於32位的機器,指標永遠佔據4byte的長度,即sizeof(指標)=4

19. 陣列名就是指向陣列指標的首地址,與指向陣列的指標相比(例如int a[]={2,3};int *p = a;),a不可以a++,但是p可以p++。在函式定義中,char *s < == > char s[].

20. *p++=value;理解為入棧,value放到p原先的位置,然後p++

val=*--p;理解為出棧,p地址首先減一,然後取值。

21. 命令列引數

#include <stdio.h>

void main(int argc,char* argv[])//或者int argc, char**argv

{

int i;

for(i=1;i<argc;i++)

{

    printf(“%s”,argv[i]);

}

}

22. 指向函式的指標

//函式的定義並宣告

void printf()

{

    printf(“Hello”);

}

void (*f)();    //指向函式的指標宣告

f = printf();    //賦值、初始化

(*f)();        //呼叫

int (*fun) (par):指向函式的指標,返回型別為int

int* fun(par):函式,返回型別為int *

23. union:單塊儲存區中管理不同型別的資料,其中所有元素相對於union基地地址的偏移為0

24. void* malloc(size_t n):返回n位元組大小的未初始化的空間

void* calloc(size_t n,size_t size):返回能夠容納nsize大小的空間

PS:

1.###分別用與轉換字串和連線字串。

#define TOSTRING(n) #n

#define CONTACT(n,m)n##m

2.i++++i效率問題:

對於原生資料,效率一樣;對於自定義型別,i++返回的是臨時變數(需要使用自增之後的值),++i返回的是引用(使用自增之後的值),效率高。

3.四位元組對齊:

#define ALIGN4(n) (((n)+3)&(~3))

4.#pragma

#pragma message("Hello") 編譯時輸出資訊

#pragma once確保該檔案被編譯一次

5.#undef用於登出之前定義的巨集變數

6.長度為0的陣列:

也成為柔性陣列,多用於佔位符。不增加型別的大小(因此使用柔性陣列而不用char*(四個位元組))。這樣一次malloc便能申請帶有緩衝區的一塊記憶體,並且是連續的記憶體。柔性陣列可以按照陣列的訪問方式進行讀取。如下:

typedefstructstrZeroTest

{

intnum;

charposition[0];

} ZeroTest;

intmain()

{

ZeroTest *pzt = (ZeroTest*)malloc(sizeof(ZeroTest)+10);

for (inti = 0; i < 10; ++i)

    {

pzt->position[i] = i;

    }

return 0;

}