C语言常量与指针

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 = &num;    //指向整数
    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 = &num;

如果将cpi初始化为指向常量limit将产生错误,因为cpi指向的数据可以修改,但是常量是不能被修改的

const int limit = 500;
int * const cpi = &limit;

指向常量的常量指针

这种类型的指针很少使用,这种指针不能修改,它指向的数据也不能通过它来修改,下面是一个例子:

const int * const cpci = &limit;

不一定只能将常量的地址赋给cpci,如下:

int num;
const int * const cpci = &num;

声明此类指针的时候必须进行初始化

指向“指向常量的常量指针”的指针

#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和指针》

时间: 2024-09-15 19:34:56

C语言常量与指针的相关文章

深入const int *p与int * const p的区别详解(常量指针与指向常量的指针)_C 语言

对于指针和常量,有以下三种形式都是正确的: 复制代码 代码如下: const char * myPtr = &char_A;//指向常量的指针char * const myPtr = &char_A;//常量的指针const char * const myPtr = &char_A;//指向常量的常量指针 下面依次对这三种类型进行介绍.因为*操作符是左操作符,左操作符的优先级是从右到左,对于1.常量指针(Constant Pointers) 复制代码 代码如下: int * con

c/c++ 函数、常量、指针和数组的关系梳理

压力才有动力,15年中旬就要准备实习,学习复习学习复习学习复习学习复习--无限循环中,好记性不如烂笔头--从数组开始,为主干. c 的array由一系列的类型相同的元素构成,数组声明包括数组元素个数和类型,c 中的数组参数是引用形式传参(传址调用),而常量标量是按值传递. //[]方括号表示声明的是数组,里面的数字表明了数组包含的元素数目 int states[50];//声明50个整数的数组 double code[365];//声明365个浮点数的数组 char chr[20];//声明20

c语言-C语言中的指针和数组的初始化

问题描述 C语言中的指针和数组的初始化 char a[]=""abcdef"";char *p =""cdefg"";a[1]='A';p[1]='A'; 这段代码有什么问题?#include int main(){ char amessage[]=""now is the time""; char *pmessage = ""now is the time"

c语言-C语言关于字符指针变量和字符数组的说法

问题描述 C语言关于字符指针变量和字符数组的说法 下列关于字符指针变量和字符数组的说法错误的是 A)字符指针变量的值可以变化 B)字符数组的值可以变化 C)字符指针变量代表了一个地址 D)字符数组代表了一个地址 ====答案选B,求解释? 解决方案 选择B.字符数组相当于指针常量. 解决方案二: 数组定义时系统给开辟内存单元,数组名相当于数组的开始地址是不能变化的 解决方案三: C语言字符指针和字符数组C语言中,为什么字符串可以赋值给字符指针变量字符数组和字符指针

c语言-C语言中二级指针修改数组问题。

问题描述 C语言中二级指针修改数组问题. 数组相当于一级指针,我写了一个二级指针被调用.结果它总是宕机,求指导,谢谢. 解决方案 这段程序编译会报错吧:cannot convert parameter 1 from 'char (*)[100]' to 'char **' 可以这样 试试看#include #include #include int getMemBuf(char*& p2){ char* tmp = NULL; tmp = (char*)malloc(100); strcpy(t

c语言-C语言中这个指针定义是什么意思?

问题描述 C语言中这个指针定义是什么意思? const char *const ch 为什么要2个const?分别是什么意思?顺便求详细说一下这个指针具体是什么意思? 编辑下,完整程序如下: #include #include #include #include int find_char(const int, const char *const, const int); int main(int argc, char argv) { bool translate = false, squeez

讲解C语言编程中指针赋值的入门实例_C 语言

从const int i 说起 你知道我们声明一个变量时象这样int i :这个i是可能在它处重新变赋值的.如下: int i = 0; /* . . . */ i = 20; /*这里重新赋值了*/ 不过有一天我的程序可能需要这样一个变量(暂且称它变量),在声明时就赋一个初始值.之后我的程序在其它任何处都不会再去重新对它赋值.那我又应该怎么办呢?用const . /* . . . */ const int ic =20; /* . . . */ ic = 40; /*这样是不可以的,编译时是无

struct-关于C语言结构体指针数组的问题

问题描述 关于C语言结构体指针数组的问题 //结构体struct student{ int iNum; char cName[16]; float fChineseScore; float fMathScore; float fEnglishScore;};typedef struct student STUDENT;//输入void InputTranscript(STUDENT MyClass[] int num){ int i; printf(""请输入学生的成绩信息:n&quo

Go语言中的指针运算实例分析_Golang

本文实例分析了Go语言中的指针运算方法.分享给大家供大家参考.具体分析如下: Go语言的语法上是不支持指针运算的,所有指针都在可控的一个范围内使用,没有C语言的*void然后随意转换指针类型这样的东西.最近在思考Go如何操作共享内存,共享内存就需要把指针转成不同类型或者对指针进行运算再获取数据. 这里对Go语言内置的unsafe模块做了一个实验,发现通过unsafe模块,Go语言一样可以做指针运算,只是比C的方式繁琐一些,但是理解上是一样的. 下面是实验代码: 复制代码 代码如下: packag