關於strcpy 和數組越界的問題

使用平臺是Ubuntu10.0 ,GCC編譯器

我們先看下面這段程序,

#include <stdio.h>
#include <string.h>

int mian(){
    char str1[] = "abcd" ;
    char str2[2];
    printf("address_str1= %p\n",str1);
    printf("address_str2= %p\n",str2);

    strcpy(str2,"123");

    printf("str1=%s\n",str1);
    printf("str2=%s\n",str2);
    
    return 0;
}
程序執行結果爲:
address_str1=0xbfe5fbb7
address_str2=0xbfe5fbb5
str1=3
str2=123

我們沒有對字符數組str1進行操作,str1[]的值不是abcd而是3 ,這是爲什麼呢?
要解決這個問題,我們首先要解決兩個問題:
1.strcpy函數的使用方法
2.局部變量在棧中是如何存儲的

一 . strcpy 函數

這是strcnp函數的原型
char *strcpy(char *dest , const char *src );
char *strncpy(char *dest , const char *src , size_t n );
使用strcpy有個缺點:strcpy進行復制時,不進行數組越界的檢查。
str2數組只有2個字節,但是"123"卻有4個字節,這是很明顯的數組越界,但是GCC編譯器編譯中沒有報錯,也就是ctrcpy複製是不進行數組越界的檢查。要避免這個問題,可以使用strncpy ,因爲strncpy有參數n來限定複製的字節數。

二.棧的知識
1、棧區(stack)—   由編譯器在程序執行過程中自動分配,在函數返回或程序結束時釋放  ,存放函數的參數值,局部變量的值等,
2、棧有棧頂和棧底,只能在棧頂進行入棧和出棧的操作。
3、棧的分類:棧分爲滿棧、空棧、遞增棧(向上增長型的)和遞減棧(向下增長型的)
4、對於8086來說,它的棧的生長方向是從高地址到地址的,因此,X86的棧是一個向下增長型的棧 (這點很重要,涉及到局部變量的存儲),即棧底爲高地址,棧頂爲低地址

三.局部變量在棧中的存儲
下面通過舉例來說明變量在棧中的存儲。
假如現在在main函數中定義三個數組:char str1[3] ,str2[4] ,str3[1]  ;
那麼系統會在程序執行過程中爲這個三個變量在棧中分配存儲空間:如下內存圖

系統會先分配三個字節來存入數組str1,然後再分配四個字節的空間來存入數組str2,最後分配一個字節空間來存入數組str3 。 這就是變量入棧的順序:str1 --> str2 --> str3  

說這麼多,其實還是沒有解決str1=3這個問題。那麼下面通過對棧的具體分析,就能獲得答案的。

我們打印str1[]的地址爲0xbfe5fbb7  ,str2[2]的地址爲0xbfe5fbb5  ,那麼程序執行時在棧中先把str1入棧,併爲str1分配5個字節 ,然後再把str2入棧,併爲str2分配2個字節。內存圖如下:

執行語句strcpy(str2,"123")時,strcpy不會進行數組越界檢查,因此會把3和\0存入str1的內存空間中,覆蓋原來存入的a 和 b 。
由於printf是行緩存,輸出遇見\0就結束。所以執行printf語句時,str1=3 ;str2 = 123


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章