欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
深入理解C語(yǔ)言

  語(yǔ)言只是一種工具,任何語(yǔ)言之間都是相通的,一通則百通,關(guān)鍵是要理解語(yǔ)言背后的思想,理解其思想,任何語(yǔ)言,拿來(lái)用就行了。語(yǔ)言沒(méi)有好壞之分,任何語(yǔ)言既然存在自然有它存在的價(jià)值。

  在一個(gè)到處是OOP的年代,為何面向過(guò)程的C語(yǔ)言依然可以如此活躍?這主要得益于C語(yǔ)言本身的語(yǔ)言特性。C語(yǔ)言小巧靈活,而且還有一個(gè)直接與硬件打交道的指針的存在,所以它是嵌入式開(kāi)發(fā)唯有的高級語(yǔ)言;正因為他的小巧靈活,我們可以用它來(lái)開(kāi)發(fā)一系列的小工具,Unix/Linux就是由這些小工具組成的操作系統;同時(shí)用C語(yǔ)言可以開(kāi)發(fā)高性能的應用程序。

1、數據類(lèi)型。C是一門(mén)面向過(guò)程的語(yǔ)言,但它依舊可以實(shí)現大多數面向對象所能完成的工作。比如面向對象的三大特性:封裝、繼承、多態(tài)。

  封裝:C中有一種復雜的數據結構叫做struct。struct是C里面的結構體。

  假如我們要對person進(jìn)行封裝,person可能包括姓名、性別、年齡、身高、體重等信息。我們就可以對它封裝如下:

struct Person{
    char name[20];//姓名
    char gender;    //性別 
    int age;        //年齡
    int height;        //身高
    int weight;      //體重
};

  當我們要像OOP那樣新建一個(gè)對象時(shí),我們就可以:

struct Person p;

  我們就可以直接對p進(jìn)行賦值:

p.name = "whc";
p.gender = 'b';  //'b' = boy; 'g' = girl
p.age = 25; 
p.height = 175;
p.weight = 65;

  繼承:同樣利用struct,我們來(lái)創(chuàng )建一個(gè)學(xué)生結構,同時(shí)繼承結構體Person,如下:

struct Student{
    struct Person p;
    char number[20]; //學(xué)號
    int score;              //成績(jì)
};

    對Student進(jìn)行創(chuàng )建對象,并賦值:

struct Student s;
s.p.name = "whc";
s.p.gender = 'b';
s.p.age = 25;
s.p.height = 175;
s.p.weight = 65;
s.number = "20150618";
s.score = 90;

  多態(tài):C中對于多態(tài)的實(shí)現可以借助函數指針來(lái)實(shí)現。為了簡(jiǎn)單起見(jiàn),我們假設Person這個(gè)結構體中,只有一個(gè)函數指針。

struct Person{
    void (*print)(void *p);
};

struct Student{
    struct Person p;
};

  而Person和Student這兩個(gè)結構體的print函數實(shí)現如下:

void printPerson(void *person){
    if(NULL == person)
        return ;
    struct Person *p = (struct Person *)person;
    printf("run in the person!!\n");
}
void printStudent(void *person){
    if(NULL == person)
        return ;
    struct Person *p = (struct Person *)person;
    printf("run in the student!!\n");
}

  我們寫(xiě)一個(gè)函數來(lái)調用他們:

void print(void *person){
    if(NULL == person)
        return ;
    struct Person *p = (struct Person *)person;
    p->print(person);
}
int main(){
    struct Person person;
    struct Student student;
    person.print = printPerson;
    student.p.print = printStudent;

    print(&person);    //實(shí)參為Person的對象
    print(&student);  //實(shí)參為Student的對象

    return 0;
}

  他們的輸出為:

  其實(shí)這個(gè)也不難理解,無(wú)論是Person還是Student,他們在內存中只有一個(gè)變量,就是那個(gè)函數指針,而void*表示任何類(lèi)型的指針,當我們將它強制轉換成struct Person*類(lèi)型時(shí),p->print指向的自然就是傳入實(shí)參的print地址。

2、 指針和內存管理

  無(wú)論問(wèn)哪一個(gè)C工程獅:C語(yǔ)言中最容易出錯的地方在哪?我們基本上會(huì )得到同一個(gè)答案,那就是指針和內存溢出。那么指針是什么,指針其實(shí)就是一個(gè)地址,這個(gè)地址可以是一個(gè)變量的地址,也可以是一個(gè)函數的地址,不管是什么,反正都是內存中的一個(gè)地址。

  例如有一個(gè)變量a,我們定義一個(gè)指針來(lái)保存變量a的地址:

int a = 0;
int *p = &a;

  如果是一個(gè)函數呢?我們定義一個(gè)函數,然后用一個(gè)函數指針來(lái)保存這個(gè)函數地址:

int min(int a,int b){
  return a<b?a:b; 
}

int (*f)(int,int);
f = min;

  可能我們有時(shí)候會(huì )想,難道我們只能先定義一個(gè)變量或者函數,然后把它的地址給指針么?不能直接使用指針,或者直接給指針賦一個(gè)常量么?首先,我們不知道內存中哪些是可用的地址,哪些是不可用的,每當我們定義一個(gè)指針時(shí),這個(gè)指針指向的是一個(gè)未定義的內存,這個(gè)就是傳說(shuō)中的野指針。如果我們給這個(gè)指針所指向的內存賦值,就有可能覆蓋了一些很重要的數據,所以每當我們定義一個(gè)指針時(shí),最好給它賦一個(gè)初始地址或者NULL;如果我們給一個(gè)指針賦常量,同樣的道理。

  指針的類(lèi)型要與變量的類(lèi)型一致(如果我們不是故意要他們不一致),所謂類(lèi)型,只是變量的一直表現形式,其實(shí)在內存中,他們不過(guò)是0101的二進(jìn)制,當我們用32bits的原碼表示時(shí),它就是unsigned;當我們用32bits補碼表示時(shí),就是signed;當用浮點(diǎn)表示時(shí)就是float;當用更復雜的自定義表示時(shí)就是struct;用union可以很好的理解這些。

  現在我們來(lái)講一下內存,這里我們只討論用戶(hù)內存區域:

  一般分為5個(gè)區域:

  (1)程序代碼區:存放代碼指令的地方

  (2)全局(靜態(tài))變量區:包括初始化、未初始化的全局變量和靜態(tài)變量

  (3)字符常量區:存放一些字符串常量,在C語(yǔ)言里面,這個(gè)很容易與棧中定義的字符數組搞混,當我們定義如下:

int main(){
  char *str0 = "Hello World!";    //字符常量區
  char  str1[] = "Hello World!";  //棧區
                       
  return 0;           
}

  str0所指向的字符串就是在字符常量區,但是str0本身的這個(gè)指針變量是在棧區的,這個(gè)變量存放的是字符常量區中"Hello World!"的首地址。

  str1是字符數組,所以str1中所存放的字符串是在棧區,這里利用的不過(guò)是字符數組初始化的一種形式,其實(shí)它可以寫(xiě)成如下形式:

char str1[] = {'H','e','l','l','o',' ','W','o','r','l','d','!','\0'};

  (4)棧區:局部變量,形參,函數返回地址等,由系統來(lái)管理,在內存里面是由高地址往低地址生長(cháng),所以??臻g大小是有限的,當在棧中定義一個(gè)很大的數組或者使用很深的遞歸調用時(shí),就有可能棧溢出。

  (5)堆區:由malloc、calloc、realloc函數分配的空間,由我們自己來(lái)管理,每次用完之后,必須用free釋放內存,否則,就會(huì )產(chǎn)生內存泄漏,每次釋放內存后,雖然不再占用著(zhù)這塊內存中,但是對應的指針依然指向這塊區域,這個(gè)指針就是野指針,所以釋放內存后,建議給指針賦NULL。如下:

int main(){
  int *p = (int*)malloc(100*sizeof(int)); 
  /*
    執行語(yǔ)句 
  */ 
  free(p);//這時(shí)p依然指向那塊內存,成了野指針
  p = NULL;  //對p賦值NULL
  return 0; 
}

3、C語(yǔ)言的I/O輸入輸出

  C語(yǔ)言本身并不帶有輸入輸出的特性,所以它的所有I/O操作都是通過(guò)系統調用來(lái)實(shí)現。幸運的是C標準庫,已經(jīng)給我們封裝好了一系列的I/O操作的函數。

  putchar ():把變量中的一個(gè)字符常量輸出到顯示器屏幕上;

  getchar ();從鍵盤(pán)上輸入一個(gè)字符常量,此常量就是該函數的值;

  printf ();把鍵盤(pán)中的各類(lèi)數據,加以格式控制輸出到顯示器屏幕上;

  scanf  ();從鍵盤(pán)上輸入各類(lèi)數據,并存放到程序變量中;

  puts    ():把數組變量中的一個(gè)字符串常量輸出到顯示器屏幕上

  gets    ():從鍵盤(pán)上輸入一個(gè)字符串常量并放到程序的數組中

  一些為對文件的操作,由于一切皆可看作是文件,標準輸入,輸出也可以當作文件來(lái)操作,文件描述符:標準輸入(0)、標準輸出(1)、標準錯誤(2)

  fputs();輸出到文件

  fgets();從文件輸入

  fscanf();格式化文件輸入

  fprintf();格式化文件輸出

  另外兩個(gè)很重要的函數,當然還有他們的派生函數也是類(lèi)似的

  sscanf(); 從一個(gè)字符串中提取各類(lèi)數據。

  sprintf(); 把格式化的數據寫(xiě)入某個(gè)字符串

  這里不對每個(gè)函數進(jìn)行詳解,主要對格式化函數進(jìn)行分析:

  (1)當我們要把一個(gè)字符串轉換成一個(gè)整數或者把一個(gè)整數轉換成一個(gè)字符串時(shí),我們一般會(huì )想到atoi()或者itoa()(非標準函數),但是我們可以通過(guò)流來(lái)實(shí)現:

int main(){
    int num = 10;
    char str[10] = {0};
    sprintf(str,"%d",num); //把int轉換成char[]
    num = 0;
    sscanf(str,"%d",&num);//把字符串轉換成int
    printf("num:%d str:%s\n",num,str);

    return 0;
}

  輸出結果如下:

  把字符串轉與其它類(lèi)型之間的轉換:比如float,16進(jìn)制,unsigned等都可以用流實(shí)現。

  (2)格式化函數中的正則表達式

  所有的格式化函數都可以定制自己的掃描集 %[abc]、%[a-z]、%[^abc]、%[^a-z],其中[]內是匹配的字符,^表示求反集。

  當我們要從標準輸入輸入一個(gè)可能帶空格的字符串時(shí),直接用scanf("%s",str);當讀到空格時(shí)就返回,此時(shí)就可以使用正則表達式:

char str[100] = {0};
scanf("%[^\n]",str);//直到遇到回車(chē)才寫(xiě)入

  從標準輸入中只要讀小寫(xiě)字母a-z,遇到其它字符則返回:

char str[100] = {0};
scanf("%[a-z]",str);

  其他格式化函數的用法相同,不一???舉例。

4、總結

  從大一開(kāi)始學(xué)習C語(yǔ)言也有四五年了,個(gè)人認為:C語(yǔ)言中最大的成功在于它的指針,但是也是最容易出錯的,想要理解C,必須要掌握指針。雖然說(shuō),語(yǔ)言只是一門(mén)工具,但是這是基礎?;蛟S,你可以說(shuō),現在是JAVA的天下了,滿(mǎn)大街都是招聘JAVA工程師;或者你可以說(shuō)C太底層,現在都是OOP的時(shí)代了,誰(shuí)還會(huì )用面向過(guò)程的......你們不要忘了操作系統是用什么寫(xiě)的?是C;C實(shí)現的nginx的并發(fā)量是C++實(shí)現的apache的幾十倍。無(wú)論是什么編程語(yǔ)言,好好學(xué),深入學(xué)就行,不要因為它今天流行就拋棄昨天所學(xué)的。

本文永久更新鏈接地址http://www.linuxidc.com/Linux/2015-08/121239.htm

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
計算機二級C語(yǔ)言歷年真題及答案
C語(yǔ)言經(jīng)典筆試題(一)
『C程序設計』讀書(shū)筆記
數組結構體總結
c語(yǔ)言
單片機C語(yǔ)言程序設計基礎知識全解析
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久