大牛查漏補(bǔ)缺 -- C語言注意點(diǎn)

前言:C語言是Java循捺、Objective-C支救、C++等高級語言的基礎(chǔ)缀雳、也是跨平臺開發(fā)的基礎(chǔ),指針是C語言的重中之重洁仗,&a表示a變量所在地址,*p表示指針p指向的地址的內(nèi)容……這些常用的性锭、常見的東西我們都比較清晰赠潦,這里就再整理一下C相關(guān)的注意點(diǎn)和一些技巧,當(dāng)做知識點(diǎn)的鞏固和完善吧草冈。

C與Linux重溫


一她奥、C 編譯過程

.c文件 -> (預(yù)處理) -> .i文件 -> (編譯) -> .s文件 -> (匯編) -> .o文件 -> (鏈接) -> 可執(zhí)行文件

  • $ gcc -o main.i main.c -E$ gcc -E main.c -o main.i:表示只執(zhí)行到預(yù)處理完成階段,生成.i文件怎棱。這個過程哩俭,是一個處理過程,①展開頭文件:將頭文件中的內(nèi)容拳恋,添加到源代碼中凡资,而不是以頭文件的形式存在;②進(jìn)行宏替換:單純的字符串替換谬运,預(yù)處理階段讳苦,宏不會考慮c的語法带膜,如下例子可以說明。
    #include <stdio.h>
    #define R 10
    #define M int main(
    
    M)
    {
      int a = R;
      //....
      return 0;
    }
    
    上述代碼經(jīng)過預(yù)處理之后鸳谜,變成了:
    ........
     <stdio.h>文件所展開的內(nèi)容膝藕,這里忽略
    ........
    int main()
    {
      int a = 10; ///R 被替換成了 10
      //.........
      return 0;
    }
    
  • 關(guān)于宏替換
    1. 特點(diǎn):直接從代碼上替換字符串,不考慮c的語法咐扭。
    2. 優(yōu)勢:可不考慮參數(shù)類型芭挽,如:#define ADD(a,b) (a+b),我們可以使用 ADD(1,2)蝗肪,也可以使用ADD(1.5,2.3)袜爪。
  • 關(guān)于typedef
    1. 與宏的區(qū)別:
    2. 宏替換在預(yù)處理過程中就執(zhí)行,而typedef在預(yù)編譯過程后的.i文件中薛闪,不會進(jìn)行任何替換操作辛馆。
    3. 宏以下的所有代碼,都可以使用到宏豁延,而typedef的作用域有限昙篙,如果定義在方法體中,就只能在方法中生效诱咏。

二苔可、Linux相關(guān)命令

  • ls -l : 輸出當(dāng)前目錄所有文件(名字或者權(quán)限等信息系)
  • echo $? :查看上一條執(zhí)行的語句的返回碼:0表示執(zhí)行成功
  • cat filename: 讀取文件filename的內(nèi)容,并顯示到終端
  • gcc main.c && ./main.c : 這個&&表示袋狞,前一句執(zhí)行成功焚辅,后一句才會開始執(zhí)行

三、關(guān)于makefile文件

  • 復(fù)習(xí):關(guān)于gcc命令選項:
    • gcc xxx -o filename:表示將xxx文件經(jīng)過處理苟鸯,輸出到名為filename的文件同蜻。(.m 結(jié)尾:Objective-C源碼文件)
    • gcc -E hello.c -o hello.i-E表示只進(jìn)行到‘預(yù)處理’階段,生成.i結(jié)尾的預(yù)處理后的C源碼文件早处。(.ii 結(jié)尾:預(yù)處理后的C++源碼文件)
    • gcc -S hello.c -o hello.s-S表示只進(jìn)行到‘匯編’階段埃仪,生成.s結(jié)尾的匯編語言源代碼文件。(-S 結(jié)尾:預(yù)處理后的匯編語言源碼文件)
    • gcc -c hello.c -o hello.o-c表示只進(jìn)行到‘編譯’階段陕赃,生成.o結(jié)尾的編譯后的目標(biāo)文件卵蛉。
    • gcc hello.c -o hello:直接生成可執(zhí)行文件。
    • gcc -g hello.c -o hello: 可執(zhí)行文件中加入調(diào)試信息
  • 意義:
    將需要編譯的多組.o和.c文件么库,他們的編譯規(guī)則和編譯順序?qū)懞迷谝粋€文件中傻丝,這樣就代替了繁雜的gcc命令。
  • 步驟
    1. 首先诉儒,在這堆c文件所在目錄下葡缰,創(chuàng)建一個文件,名為Makefile
    $ vi Makefile
    
    1. 然后,輸入該文件的內(nèi)容如下:
    # this is make file
    main.out:lib1.o lib2.o main.c -o hello.out
    [兩個Tab泛释,表示8個空格]gcc lib1.o lib2.o main.c
    lib1.o:lib1.c
    [兩個Tab滤愕,表示8個空格]gcc -c lib1.c
    lib2.o:lib2.c
    [兩個Tab,表示8個空格]gcc -c lib2.c
    
    1. 保存文件怜校,最后间影,在這個目錄下,執(zhí)行make命令:
    make
    

四茄茁、關(guān)于C的main函數(shù)

///其中:argv表示執(zhí)行時帶有的參數(shù)個數(shù)魂贬,argc表示執(zhí)行時所帶參數(shù)列表。
int main(int argv, char* argc[]){
  //doSomething;
  return 0;///執(zhí)行之后裙顽,返回值(0表示成功)
}

例如執(zhí)行:./ main.out -a -l -d付燥,那么,argv=4愈犹,argc分別為:./main.out键科,-a-l漩怎,-d勋颖。

五、C的標(biāo)準(zhǔn)輸入輸出流和錯誤流

我們知道扬卷,include <stdio.h>的這個頭文件牙言,在我們執(zhí)行應(yīng)用程序的瞬間酸钦,操作系統(tǒng)為程序啟動了一個進(jìn)程怪得,之后,當(dāng)包含進(jìn)這個頭文件后卑硫,它會給我們提供一系列指針徒恋,指向資源,應(yīng)用程序被啟動時欢伏,他會為我們創(chuàng)建三個文件入挣,分別是:stdin、stdout硝拧、stderr径筏,分別對應(yīng)于:標(biāo)準(zhǔn)輸入、輸出和錯誤流障陶,負(fù)責(zé)為我們的應(yīng)用程序提供輸入和輸出數(shù)據(jù)的能力滋恬。

  • stdin:標(biāo)準(zhǔn)輸出流,默認(rèn)是我們的屏幕顯示器終端
    printf("hello\n");底層是:fprintf(stdin, "hello\n");
  • stdout:標(biāo)準(zhǔn)輸入流抱究,默認(rèn)設(shè)備是我們的鍵盤
    scanf("%d", &n);底層是:fscanf(stdout, "%d", &n);
  • stderr:標(biāo)準(zhǔn)錯誤流恢氯,報告程序出錯時的輸出操作:
    if(……){
      fprintf(stderr, "error!");
      return 1;//這里很關(guān)鍵,返回不是0,表示程序執(zhí)行有錯誤勋拟。
    }
    

六勋磕、重定向機(jī)制

  • 輸出重定向

    1. 把程序的輸出流,重定向到一個新的文件中敢靡,填充文件內(nèi)容【不覆蓋】:
    ./main.out >> output.txt
    //或者
    ./main.out  1>> output.txt
    
    1. 把上一步執(zhí)行的結(jié)果挂滓,重定向到一個文件中,覆蓋文件內(nèi)容:
    ls /etc > etc.txt
    
    1. 標(biāo)準(zhǔn)輸出流和標(biāo)準(zhǔn)錯誤流分別輸出到不同文件醋安,正常輸出為true.txt 杂彭,錯誤輸出為fail.txt:
      main.c代碼如下:
    #Include<stdio.h>
    int main(){
      int a,b;
      scanf("%d", &a);
      scanf("%d", &b);
      if(0!=b)
        printf("a/b=%d\n", a/b);
      else{
        fprintf(stderr, "j!=0\n");
        return 1;
      }
      return 0;
    }
    

    命令行輸入如下:

    $ cc main.c -o main.out
    $ ./main 1>true.txt  2>fail.txt
    ////如果有輸入的文件,還可以:
    // $ ./main 1>true.txt  2>fail.txt  <input.txt
    
  • 輸入重定向

    1. 將要輸入的參數(shù)值吓揪,寫入一個文件input.txt中亲怠,然后代替鍵盤鍵入:
    ./main.out < input.txt
    

七、結(jié)構(gòu)體相關(guān)

  1. 結(jié)構(gòu)體定義與數(shù)組賦值
struct person{
  char name[20];
  int age;
};////可以在“;”號前直接定義一個全局變量為me
.......
int main()
{
  struct person team[2] = {"xiao_ming", 20, "hua_zai",18};
  //或者:struct person team[2] = {{"xiao_ming", 20}, {"hua_zai",18}};
}
  1. 結(jié)構(gòu)體指針
  • 指向單個結(jié)構(gòu)體對象
struct person xiaoming = {"xiaoming", 19};
struct person * p1;
p1 = &xiaoming;
printf("name=%s\n", (*p1).name);///也可以寫成:p1->name 或者 xiaoming.name  柠辞,這三種方法是等價的团秽。
  • 指向結(jié)構(gòu)體數(shù)組對象
struct person team[2] = {{"xiao_ming", 20}, {"hua_zai",18}};
struct person * p;
p = team; //沒有了‘&’
printf("name=%s\n", p->name);///相當(dāng)于 team[0].name
printf("name=%s\n", (++p)->name);///相當(dāng)于 team[1].name
  1. 結(jié)構(gòu)體的大小【重要】
    <u>結(jié)構(gòu)體大小 = 結(jié)構(gòu)體最后一個成員的偏移量 + 最后一個成員的大小 + 末尾的填充字節(jié)數(shù)</u>
    例子:
struct data{
  int a;///偏移量為0
  char b;///偏移量為4【因為偏移量‘4’是b本身大小‘1’的整數(shù)倍,所以叭首,編譯器不會在成員a和b之間填充字節(jié)】
  int c;///偏移量為5 --> 8【編譯器在b后面填充了字節(jié)习勤,本來是5,最后變成8焙格,因為8才是4的整數(shù)倍】
  ///這樣一來图毕,整個data結(jié)構(gòu)體的大小是 4+4(1+3)+4=12 ,而判斷得出:12%4(最寬的基本類型int的大小) == 0眷唉,所以予颤,最終大小不會再被編譯器填充字節(jié),就是12冬阳。
}

八蛤虐、聯(lián)合體

  1. 聯(lián)合體的定義
union data{ ///聯(lián)合體 data,它所占的內(nèi)存空間為最大元素所占的空間肝陪,所以驳庭,為4byte。
  int a;
  char b;
  int c;
}

九氯窍、動態(tài)鏈表與靜態(tài)鏈表

  1. 兩者都是動態(tài)數(shù)據(jù)結(jié)構(gòu)
///鏈表結(jié)點(diǎn)結(jié)構(gòu)體
struct node{
  int data;
  node * next;
};
  1. 兩者的區(qū)別
  • 靜態(tài)鏈表寫法
    main方法中:
///main方法中
struct node a,b,c, * head;
a.data = 1;
b.data = 2;
c.data = 3;
a.next = b;
b.next = c;
c.next = NULL;
head = &a;
///以head為頭結(jié)點(diǎn)指針的靜態(tài)鏈表創(chuàng)建成功
///...............
struct node *p = head;
while(p->NULL){
  printf("%d\n", p->data);
  p = p->next;
}
  • 動態(tài)鏈表寫法

include <stdio.h>

include <stdlib.h>//當(dāng)中有malloc相關(guān)api

///鏈表結(jié)點(diǎn)結(jié)構(gòu)體
struct node{
int data;
node * next;
};
///創(chuàng)建鏈表的函數(shù)
struct node * create(){
struct node head;
struct node p1,p2;
int n = 0;
p1 = p2 = (struct node
)malloc(sizeof(struct node));
scanf("%d", &p1->data);
head = NULL;
while(p1->data!=0){
n++;
if(n==1) head = p1;
else p2->next = p1;
p2 = p1;
p1 = (struct node*)malloc(sizeof(struct node));
scanf("%d", &p1->data);
}
p2 ->next = NULL;
return (head);
}
///main方法中
int main(){
struct node * p;
p =create();
printf("第一個結(jié)點(diǎn)的信息:%d\n", p->data);
return 0;
}
```

十饲常、C語言的變量存儲類別

  • 根據(jù)變量的生命周期來劃分,分為:靜態(tài)存儲方式和動態(tài)存儲方式
    • 靜態(tài)存儲方式:指在程序運(yùn)行期間分配固定的存儲空間的方式狼讨。存放了在整個程序執(zhí)行過程中都存在的變量(如:全局變量)
    • 動態(tài)存儲方式:在程序運(yùn)行期間更具需要進(jìn)行動態(tài)的分配存儲空間的方式贝淤。動態(tài)存儲區(qū)中存放的變量是根據(jù)程序運(yùn)行的需要而建立和釋放的。(如:函數(shù)形參熊楼、自動變量霹娄、函數(shù)調(diào)用時的現(xiàn)場保護(hù)和返回地址等)
  • C語言中的存儲類別:自動(auto)能犯、靜態(tài)(static)、寄存器(register)和外部(extern)
    • 自動(auto): 用關(guān)鍵字auto定義的變量為自動變量犬耻,auto可以省略踩晶,auto不寫則隱含定為“自動存儲類別”,屬于動態(tài)存儲方式枕磁。如:auto int a;相當(dāng)于int a;

    • 靜態(tài)(static): 用static修飾的為靜態(tài)變量渡蜻,如果定義在函數(shù)內(nèi)部的,稱之為靜態(tài)局部變量计济;如果定義在函數(shù)外部茸苇,稱之為靜態(tài)外部變量。如下為靜態(tài)局部變量沦寂。

      int func(){
        static int a = 1;
        a++;
        printf("a = %d\n", a);
      }
      int main(){
        int i = 0;
       for(;i<10;i++){  func(); }///最終得到:a = 1,a = 2,..., a = 10
      }
      

      注意:靜態(tài)局部變量屬于靜態(tài)存儲類別学密,在靜態(tài)存儲區(qū)內(nèi)分配存儲單元,在程序整個運(yùn)行期間都不釋放传藏;靜態(tài)局部變量在編譯時賦初值腻暮,即只賦初值一次;如果在定義局部變量時不賦初值的話毯侦,則對靜態(tài)局部變量來說哭靖,編譯時自動賦初值0(對數(shù)值型變量)或空字符(對字符變量)

    • 寄存器(register): 為了提高效率侈离,C語言允許將局部變量得值放在CPU中的寄存器中试幽,這種變量叫“寄存器變量”,用關(guān)鍵字register作聲明卦碾。如register int a = 1;

      注意:只有局部自動變量形參可以作為寄存器變量铺坞;一個計算機(jī)系統(tǒng)中的寄存器數(shù)目有限,不能定義任意多個寄存器變量蔗坯;局部靜態(tài)變量不能定義為寄存器變量康震。

    • 外部(extern): 用extern聲明的的變量是外部變量燎含,外部變量的意義是某函數(shù)可以調(diào)用在該函數(shù)之后定義的變量宾濒。

      int main(){
        extern int b;
        printf("%d\n" , b);///實際上是調(diào)用main函數(shù)之后的代碼中的全局變量b,結(jié)果為100.
      }
      int b = 100;
      

十一屏箍、C語言的內(nèi)部函數(shù)與外部函數(shù)

  • 內(nèi)部函數(shù):
    • 定義:在C語言中不能被其他源文件調(diào)用的函數(shù)稱謂**內(nèi)部函數(shù) **绘梦,內(nèi)部函數(shù)由static關(guān)鍵字來定義,因此又被稱謂靜態(tài)函數(shù)赴魁。
    • 形式:static [數(shù)據(jù)類型] 函數(shù)名([參數(shù)])
  • 外部函數(shù):
    • 定義:能被其他源文件調(diào)用的函數(shù)稱謂**外部函數(shù) **卸奉,外部函數(shù)由extern關(guān)鍵字來定義。
    • 形式:extern [數(shù)據(jù)類型] 函數(shù)名([參數(shù)])

    C語言規(guī)定颖御,在沒有指定函數(shù)的作用范圍時榄棵,系統(tǒng)會默認(rèn)認(rèn)為是外部函數(shù),因此當(dāng)需要定義外部函數(shù)時extern也可以省略C語言規(guī)定,在沒有指定函數(shù)的作用范圍時疹鳄,系統(tǒng)會默認(rèn)認(rèn)為是外部函數(shù)拧略,因此當(dāng)需要定義外部函數(shù)時extern也可以省略。

Linux 操作系統(tǒng)下對于C語言的內(nèi)存管理和分配


一瘪弓、32位和64位操作系統(tǒng)

操作系統(tǒng)理論上會將我們安置的內(nèi)存條的所有地址空間進(jìn)行編號(從000……0 到 111……1)垫蛆,直到它所能區(qū)分的位置總數(shù)(比如:我插了兩條4G內(nèi)存條到64位OS下的電腦時,理論上腺怯,就能將整個內(nèi)存區(qū)分成 2的33次方 個位置)

  • 32位操作系統(tǒng)只能使用4G內(nèi)存(由于CPU的地址總線為32位袱饭,對應(yīng)的尋址空間大小為2的32次方,也就是說:“我最多區(qū)分出 2的32次方 個不同的位置”)
  • 64位操作系統(tǒng)可以使用足夠大的內(nèi)存

二呛占、用戶內(nèi)存隔離

  • 首先虑乖, 內(nèi)存管理和分配是由操作系統(tǒng)來幫我們完成的。
  • 64位操作系統(tǒng)中晾虑,對于內(nèi)存分配:
    • 0xffffffffffffffff ~ 0x8000000000000000:系統(tǒng)程序使用內(nèi)存【前16位】
    • 0x7fffffffffffffff ~ 0x00:用戶程序使用內(nèi)存【后48位】
  • 用戶內(nèi)存分配結(jié)構(gòu):
    1. 代碼段【內(nèi)存中的最低段位】:代碼編譯后的二進(jìn)制數(shù)據(jù)加載到內(nèi)存中的最低位處决左,即:代碼段
    2. 數(shù)據(jù)段【內(nèi)存中的第二低段位】:聲明一些全局變量(全局或函數(shù)中的)靜態(tài)變量或者常量走贪,則放在了數(shù)據(jù)段處
    3. 堆【內(nèi)存中的第三低段位】
    4. 自由可分配內(nèi)存【內(nèi)存中的第四低段位】
    5. 椃鹈停【內(nèi)存中的第二高段位,最高段位是系統(tǒng)內(nèi)存】:記錄函數(shù)當(dāng)前運(yùn)行時的狀態(tài)坠狡,記錄“代碼運(yùn)行到第幾行继找,內(nèi)部的變量所在內(nèi)存地址等信息等(如:main函數(shù)開頭連續(xù)聲明兩個int類型變量a和b,那么逃沿,a和b所在內(nèi)存地址數(shù)之間差為4個字節(jié))”婴渡。一個函數(shù)可能被多次調(diào)用,而每次調(diào)用函數(shù)凯亮,都是一個獨(dú)立的棧边臼;先聲明的函數(shù)所處內(nèi)存地址位置低,后聲明的函數(shù)所處內(nèi)存地址位置高假消,而系統(tǒng)對棧的地址分配則相反柠并,先分配的棧所在地址更高(如:main方法調(diào)用方法A,那么對main方法分配的棧比對方法A分配的棧地址位置高富拗,)臼予;
操作系統(tǒng)對內(nèi)存的管理和分配
  • gcc對內(nèi)存分配的優(yōu)化
    • 首先,在程序代碼編譯后啃沪,gcc編譯器會將零碎的聲明的所有非靜態(tài)變量粘拾,按照類型進(jìn)行歸類,同一類型的變量聲明在一塊创千,然后去為每一類的變量集合分配內(nèi)存缰雇。這樣一來入偷,同一類型的變量實際在內(nèi)存的棧空間中的位置是相鄰的械哟。
    • 對C語言來說盯串,32位OS中,指針變量占4byte戒良;64位OS中体捏,指針變量占8byte。

三糯崎、函數(shù)棧几缭、函數(shù)指針

  • (一)函數(shù)棧
    ?C中的函數(shù)調(diào)用,每一個函數(shù)的調(diào)用沃呢,系統(tǒng)都會為其分配一個棧年栓,用于存放這個函數(shù)的信息(目前執(zhí)行第幾行、成員變量的信息等)薄霜,這個就是函數(shù)棧某抓。【注意:函數(shù)內(nèi)部的靜態(tài)變量位于內(nèi)存中的數(shù)據(jù)段惰瓜,而非棧區(qū)】
  • (二)函數(shù)指針
    ?看個例子:
#include<stdio.h>
int func(int a){
    return a*a;
}
int main(){
   int b = 3;
   int res;
   res = (*func)(b);
   printf("%d\n",res);
   return 0;
}

這里的res = (*func)(b);指的就是:調(diào)用func(3)否副,并將返回值賦給res。其中崎坊,func表示func函數(shù)所在代碼段中的地址本身备禀,(*func)表示找到這個func名對象對應(yīng)的代碼段中此函數(shù)打包塊,相當(dāng)于獲取到整個函數(shù)奈揍。

四曲尸、指針運(yùn)算

  • (一)高效率的指針偏移
    前面說過,由于gcc對變量指向內(nèi)存地址的優(yōu)化男翰,同一類對象會被歸在一段連續(xù)分配的內(nèi)存中另患。為什么說“高效率”?因為每次指針偏移“1”蛾绎,就能準(zhǔn)確地定位到原地址的下一個對象存儲的首地址昆箕,此過程是根據(jù)類型大小而適配的,相對于for循環(huán)秘通,指針偏移只需要內(nèi)部執(zhí)行一條偏移語句即可为严,所以會“更高效率”敛熬。
    ?下面看看這個示例:

    #include<stdio.h>
    int main(){
      int a = 3;
      int b = 2;
      int arr[3];
      int *p = &a;
      arr[0] = 1;
      arr[1] = 10;
      arr[2] = 100;
      p+=3;///注意點(diǎn)一
      *p = 4;
      p = &a;
      int i;///注意點(diǎn)二
      for(i=0;i<6;i++){
         printf("*p = %d  , p[%d] = %d\n", *(p+i), i, p[i]);///注意點(diǎn)三
      }
      return 0;
    }
    

    打印結(jié)果為:

    *p = 3 , p[0] = 3
    *p = 1 , p[1] = 1 //注意點(diǎn)四
    *p = 2 , p[2] = 2
    *p = 4 , p[3] = 4
    *p = 10 , p[4] = 10
    *p = 100 , p[5] = 100
    

    以上的示例代碼中肺稀,有三個注意點(diǎn),用注釋標(biāo)記出來:

    1. 注意點(diǎn)一:p+=3; *p=4;等價于:①p[3]=4*(p+3) = 4应民,相當(dāng)于讓p所指的地址之后的第三個地址賦上4话原。
    2. 注意點(diǎn)二和注意點(diǎn)四:這里就可以結(jié)合以上說的 ‘gcc對變量和內(nèi)存地址指向的優(yōu)化’ 來解釋夕吻,gcc將同一類型的變量放在連續(xù)分配的內(nèi)存空間中排列,于是繁仁,當(dāng)p指向a的地址涉馅,a地址和b地址之間,還存在變量i所在的地址(由于gcc的優(yōu)化整理)黄虱,所以稚矿,這里才有了p[1]=1;
    3. 注意點(diǎn)三:這里可以得出,指針運(yùn)算中捻浦,*(p+n)p[n]效果是一樣的晤揣。

    注意:這里專指Linux64位系統(tǒng)下gcc對C語言的相關(guān)優(yōu)化支持,在MacOS或其他系統(tǒng)下朱灿,可能會有一定差異昧识。

  • (二)字符數(shù)組和指針字符串
    看看一下示例:

#include<stdio.h>
int main(){
  char s[] = "hello";
  char *s2 = "world";
  char s3[10];
  scanf("%s", s3);
  printf("%s, %s ,%s\n", s,s2,s3);
}

注意點(diǎn):

  • 首先,這段代碼盗扒,三個變量s跪楞、s1、s2都是可以正常輸出的侣灶。
  • s[] 被當(dāng)成一個值甸祭,而 s2 被當(dāng)成一個指針,指向這個“world”的首地址褥影。
  • 此時淋叶,可以看出,指針和字符數(shù)組可以適當(dāng)混用伪阶,在輸入s3時煞檩,可知,s3本身指代一個內(nèi)存地址栅贴,所以不用加“&”符號【 s 同理】斟湃。
  • 但是,如果是要輸入到s2中檐薯,就不行了凝赛。因為C語言中,字符數(shù)組的大小等于字符數(shù)加上“\0”坛缕,這個“\0”是結(jié)束符號(比如上述的s[]的大小就是6個字節(jié))墓猎,而*s2本身是指針類型,指向的是內(nèi)存的代碼段中的“world”(由gcc編譯時決定的赚楚,會認(rèn)為s2指向的是"world"字符串常量)毙沾,而不是棧空間宠页,而代碼段中的成員是沒有修改權(quán)限的左胞,棧和堆中的對象才可以修改寇仓。
  • 溢出的情況:如果是scanf("%s" , s);,那么如果輸入超過6個字符烤宙,那么遍烦,原來s的末尾的\0結(jié)束符將被覆蓋,而上述示例中躺枕,由于gcc優(yōu)化服猪,ss3的內(nèi)存地址實際上是相鄰的,s原始占有6個字節(jié)拐云,而s3原始占有10個字節(jié)蔓姚,那么,如果輸入大串字符慨丐,則會覆蓋s甚至s3的原來的內(nèi)容甚至其他內(nèi)存空間的內(nèi)容坡脐,這樣一來,就會造成很嚴(yán)重的后果7拷摇备闲!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市捅暴,隨后出現(xiàn)的幾起案子恬砂,更是在濱河造成了極大的恐慌,老刑警劉巖蓬痒,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泻骤,死亡現(xiàn)場離奇詭異,居然都是意外死亡梧奢,警方通過查閱死者的電腦和手機(jī)狱掂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亲轨,“玉大人趋惨,你說我怎么就攤上這事〉胛茫” “怎么了器虾?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蹦锋。 經(jīng)常有香客問我兆沙,道長,這世上最難降的妖魔是什么莉掂? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任葛圃,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘装悲。我一直安慰自己昏鹃,他們只是感情好尚氛,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布诀诊。 她就那樣靜靜地躺著,像睡著了一般阅嘶。 火紅的嫁衣襯著肌膚如雪属瓣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天讯柔,我揣著相機(jī)與錄音抡蛙,去河邊找鬼。 笑死魂迄,一個胖子當(dāng)著我的面吹牛粗截,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播捣炬,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼熊昌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了湿酸?” 一聲冷哼從身側(cè)響起婿屹,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎推溃,沒想到半個月后昂利,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铁坎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年蜂奸,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片硬萍。...
    茶點(diǎn)故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡窝撵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出襟铭,到底是詐尸還是另有隱情碌奉,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布寒砖,位于F島的核電站赐劣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏哩都。R本人自食惡果不足惜魁兼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望漠嵌。 院中可真熱鬧咐汞,春花似錦盖呼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至植阴,卻和暖如春蟹瘾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掠手。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工憾朴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喷鸽。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓众雷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親做祝。 傳聞我的和親對象是個殘疾皇子砾省,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容