C語言功能強大而豐富,還表現在const與指針的結合使用上,對不同的問題,它提供不同的保護,特別有用的是指向常量的指針
本文地址:http://www.cnblogs.com/archimedes/p/c-const-point.html,轉載請注明源地址。
可以將指針指向常量,這就意味著不能通過指針修改它所引用的值
int num = 5; const int limit = 500; int *pi; const int *pci; pi = # //指向整數 pci = &limit; //指向整數常量
下面的代碼會打印這些變量的地址和值:
#include <stdio.h>
int main(void)
{
int num = 5;
const int limit = 500;
int *pi;
const int *pci;
pi = # //指向整數
pci = &limit; //指向整數常量
printf(" num - Address:%p value:%d\n", &num, num);
printf("limit - Address:%p value:%d\n", &limit, limit);
printf(" pi - Address:%p value:%p\n", &pi, pi);
printf(" pci - Address:%p value:%p\n", &pci, pci);
return 0;
}
不能解引指向常量的指針並改變指針所引用的值,但是指針的值不是常量,可以改變指針,指針可以改為引用另一個整數常量或普通整數
把pci聲明為指向整數常量的指針意味著:
pci可以被修改為指向不同的整數常量
pci可以被修改為指向不同的非整數常量
可以解引pci以讀取數據
不能解引pci從而修改它指向的數據
注意:數據類型和const的順序無關緊要,可以互換
const int *pci = int const *pci
指針不可變,但是它指向的數據可變
int num; int *const cpi = #
如果將cpi初始化為指向常量limit將產生錯誤,因為cpi指向的數據可以修改,但是常量是不能被修改的
const int limit = 500; int * const cpi = &limit;
這種類型的指針很少使用,這種指針不能修改,它指向的數據也不能通過它來修改,下面是一個例子:
const int * const cpci = &limit;
不一定只能將常量的地址賦給cpci,如下:
int num; const int * const cpci = #
聲明此類指針的時候必須進行初始化
#include <stdio.h>
int main(void)
{
const int limit = 500;
const int * const cpci = &limit;
const int * const * pcpci = &cpci;
printf("%d\n", *cpci);
printf("%d\n", **pcpci);
return 0;
}
下表總結所討論的四種指針:
指針類型 指針是否可修改 指向指針的數據是否可修改 指向非常量的指針 是 是 指向常量的指針 是 否 指向非常量的常量指針 否 是 指向常量的常量指針 否 否下面的例子中,function函數返回一個指向結構體常量的指針,意味著結構體中的值是只讀的,限定符很有用,因為它告訴我們一些不能進行的操作
#include<stdio.h>
#include<stdlib.h>
struct a
{
int x;
};
const struct a * function(void)
{
struct a *ptr;
if((ptr = (struct a *)malloc(sizeof(struct a))) == NULL)
exit(1);
ptr->x = 0;
return ptr;
}
int main(void)
{
int y;
const struct a *ptr;
ptr = function();
y = ptr->x;
return 0;
}
如果我們試圖修改,我們將得到一個gcc error
int main(void)
{
int y;
const struct a *ptr;
ptr = function();
ptr->x = 1;
return 0;
}
error: assignment of read-only location ‘*ptr’
如果將值賦值給一個非結構體常量,我們將得到gcc的警告
int main(void)
{
int y;
struct a *ptr;
ptr = function();
ptr->x = 1;
return 0;
}
warning: assignment discards qualifiers from pointer target type
如果使用類型轉換將可以成功運行
int main(void)
{
struct a *ptr;
ptr = (struct a *) function();
ptr->x = 1;
return 0;
}
結構體常量指針作為參數
#include<stdio.h>
#include<stdlib.h>
struct a
{
int x;
};
struct b
{
const struct a *nested_ptr;
};
const struct a * function(void)
{
struct a *ptr;
if((ptr = (struct a *) malloc(sizeof(struct a))) == NULL){
exit(1);
}
ptr->x = 0;
return ptr;
}
void do_something(const struct b *ptr)
{
const struct a *x = ptr->nested_ptr;
}
int main(void)
{
struct b b_obj;
b_obj.nested_ptr = function();
do_something(&b_obj);
return 0;
}
常量指針
將一個指針指定為常量的,const關鍵字放在"*"的後面,就像上面的do_something()原型可以改寫為下面的形式,所有的都不可以修改,ptr變量通過調用傳遞參數初始化,以後就不能修改
void do_something(const struct b * const ptr);
常量初始化延伸
一個結構體常量可以像下面這樣初始化:
int main(void)
{
const struct a obj = [ 5 ];
return obj.x;
}
一個指向結構體常量的指針可以像下面這樣初始化:
int main(void)
{
const struct a obj = [ 5 ];
const struct a *ptr_a = &obj;
const struct a *ptr_b = function();
return ptr_a->x;
}
返回常量指針
const struct a * const function(void);
傳遞指向常量指針的指針
一個常見傳遞二重指針的原因就是需要修改指針值,看下面的例子:
void fill_in(const struct a **location)
{
*location = function();
}
int main(void)
{
const struct a *ptr;
fill_in(&ptr);
return 0;
}
再看下面的代碼,在location前面加上const
void fill_in(const struct a ** const location)
{
*location = function();
}
解釋如下:
1、結構體是常量的,內容不能修改
2、指向該結構體的指針,通過location指向,*location不是常量,可以修改
3、變量location是常量的,意味著不能被修改
還可以添加一個const:
void fill_in(const struct a * const * const location)
{
*location = function();
}
error: assignment of read-only location ‘*location’ (由於*location也是常量,所以會得到gcc error)
下面的代碼不是操作結構體的內容,也不是指向結構體的指針,而是允許函數通過傳遞的參數操作它自身的局部變量
void make_use_of(const struct a * const *location)
{
const struct a * const ptr_a = *location;
const struct a *ptr_b = *location;
ptr_b = NULL;
location = NULL;
}
解釋如下:
1、結構體是常量的,內容不能修改
2、指向該結構體的指針,通過location指向,*location也是常量,不可以修改
3、變量location是非常量,意味著可以被修改
4、局部變量ptr_a是常量,不可以被修改
4、局部變量ptr_a不是常量,可以被修改
維基百科
《C和指針》