標籤:
程式筆試題-const變數通過指標修改問題 2012-10-06 20:45:18
分類: C/C++
const的變數在特定情況下可以通過指標修改,但是在另一些情況下是不能通過指標修改。以下是VC6下才測試。1 不能修改的情況#include <stdio.h>
int const a = 10;
void main(void)
{
int *p = (int*)&a;
*p = 20;
printf("%d\n", *p);
}程式編譯通過,但執行階段錯誤:指示a儲存的空間不可以寫,也就是沒有寫入權限,不能修改其值。估計是儲存在全域空間,且只有可讀屬性。 2 能修改的情況#include <stdio.h>
void main(void)
{
int const a = 10;
int *p = (int*)&a;
*p = 20;
printf("&a=%d\n", &a);
printf(" p=%d\n", p);
printf(" a=%d\n", a);
printf("*p=%d\n", *p);
}程式能正常運行,且常量被修改了,但是有一個問題: 為什麼 printf(" a=%d\n", a); 列印a=10?難道一個地址空間可以儲存不同的倆個值,當然不能,哈哈,這是因為a是const變數,編譯器對a在預先處理的時候就進行了替換。編譯器只對const變數的值讀取一次。所以列印的是10。a實際儲存的值發生了改變。但是為什麼能改變呢,從其儲存地址可以看出來,其儲存在堆棧中。驗證如下:#include <stdio.h>
void main(void)
{
int const a = 10;
int b = 20;
int *p = (int*)&a;
*p = 20;
printf("&a=%x\n", &a);
printf("&b=%x\n", &b);
printf(" p=%x\n", p);
printf(" a=%d\n", a);
printf("*p=%d\n", *p);
}變數a和b的地址相近。
總結,const全域變數儲存在全域儲存空間,其值只有可讀屬性,不能修改;
const局部變數儲存在堆棧中,可通過指標修改其值;
const變數在預先處理是處理,編譯器只對其值讀取一次。
知乎上回答
const在C語言中是表示道義上保證變數的值不會被修改,並不能實際阻止修改,通過指標可以修改常變數的值,但是會出現一些不可知的結果。幾種情況不同,我們一個一個來看。
1、直接賦值
const int a = 3;a = 5;// const.c:6:2: error: assignment of read-only variable ‘a’
這種情況不用多說,編譯錯。
2、使用指標賦值,@孫健波提到的方法,在gcc中的warning,g++中出現error,是因為代碼寫得不對,由非const的變成const不用顯式的轉換,const變為非const需要顯式轉換,這種情況應當使用顯式的類型轉換。
const int a = 3;int* b = (int*) &a;printf("a = %d, *b = %d\n", a, *b);*b = 5;printf("a = %d, *b = %d\n", a, *b);
運行結果(註:使用msvc編譯的結果一致):
$ gcc const.c$ ./a.outa = 3, *b = 3a = 5, *b = 5$ g++ const.cpp$ ./a.outa = 3, *b = 3a = 3, *b = 5
這裡使用g++編譯時間,a的值之所以沒有改變,是因為編譯時間a是常量,然後被編譯器編譯為立即數了。因此對使用b指標修改不會更改a的值。
值得注意的是,如果a被定義為全域常變數,使用指標修改會引發segment fault。
在函數的原型中,我們也常用const修飾指標,表示函數的實現者在道義上不會去修改這個指標所指向的空間。例如我們熟知的strcpy函數,原型如下:
char* strcpy(char* dst, const char* src);
傳入的參數src類型是const char*,表示函數內部實現不會修改src所指向的空間。之所以說是道義上,是因為在內部通過上述指標強制類型轉換的方式可以修改該空間的值。另外,如果我們聲明了我們不會修改傳入指標的所指向的空間,那麼我們也不應當去修改這塊空間,因為這個傳入的指標可能會是一個不可寫的記憶體,然後出現段錯誤。
(轉)const變數通過指標修改問題