char* a 与 char a[] 以及常量指针,指针常量

本文详细解析常量指针与指针常量的概念、使用方式及区别,通过代码实例展示了两者在操作数据时的不同行为,并揭示了字符串常量与字符数组在内存存储上的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

常量指针与指针常量

  • 常量指针 :指向常量值的指针,指针本身值可变,但是指针所指向的内容不可更改

  • 指针常量:指针值是一个常量,即指针值不可变,但指针所指向的内容可以变

如:

int a = 9;
int const * ptr = &a;

在这里ptr为常量指针

int a = 9;
int * const ptr = &a;

此时ptr为指针常量

读法:当*在const前面时,叫做指针常量,当const在*前面时,读作常量指针

那么这两个有什么区别呢?
看下面两段代码:

#include<stdio.h>

int main(void)
{
    int a = 9;
    int b = 8;
    int c = 7;

    int * const ptr = &a;
    int const * p = &b;

    *ptr = 1;

    // 1: ptr++;   

    p = &c;

    // 2: *p = 1;

    return 0;
}

这个程序运行正常
这里写图片描述

但是去掉注释1的话,就会报错了~
这里写图片描述

当去掉注释2的话,也会报错~
这里写图片描述

因为ptr为指针常量,所以不可以更改其指针值
而p为常量指针,不可以更改其指向的内容

char* a 与 char a[]

char* a = "good";
char b[20] = "good";

a是指向第一个字符’g’的指针
b是指向字符数组第一个元素’g’的指针
二者看似相同,然而并非如此

现在就让我们来揭开其神秘的面纱

#include<stdio.h>

int main(void)
{
    char* a = "helloworld";

    a[0] = 'g';

    return 0;
}

这段代码看似没有问题,但当我们运行时,会出现如下结果:
这里写图片描述

而当代码为这样的时候:

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    char a[20] = "helloworld";

    a[0] = 0;

    system("pause");
    return 0;
}

其结果为:
这里写图片描述
运行正常~~

照成这一切的差异是什么呢?
字符串常量是放在常量区的,只可读。而字符数组是存在于栈中的,可以修改其数据
因此:
char* a = “helloworld”; “helloworld”是存放于常量区,因此只可读不可写
char a[20] = “helloworld”; “helloworld”存在于栈内,可读可写

char a[20] = “helloworld”;由于存放于栈中,因此读取速度比char* a = “helloworld”快

char * a = “helloworld”在编译时便已经确定了值
char a[20] = “helloworld”则是在运行时确定的

当执行char a[] = “helloworld”;时,系统将会分配11个字节的空间,最后一个字节存放’\0’,当调用strlen(a)时得到的值为10,因此strlen()不会将’\0’计算进去

内存存储模式

静态储存区:编译时确定,用于存放常量,全局变量等
栈:用于存放变量,运行时分配
堆:动态分配,可使用new,malloc分配,需手动释放

参考文章:
char*与char[]的区别

### 解析 `*(const char **)a` 的含义 #### 1. **语法结构解析** 表达式 `(const char **)a` 表示将指针变量 `a` 转换为类型为 `const char**` 的指针。具体来说: - `const char*` 是一种指向常量字符的指针,意味着通过该指针无法修改其所指向的数据。 - `const char**` 则是一个指向 `const char*` 类型的指针。 因此,`(const char**)a` 的作用是告诉编译器:假设 `a` 实际上存储的是一个地址,这个地址指向另一个地址,而那个地址又指向一个不可变的字符串(即 `const char*`)。[^1] 接着,`*(const char**)a` 表达式的含义是对经过强制转换后的指针解引用,得到它所指向的第一个层次的对象——也就是一个 `const char*` 类型的指针。 --- #### 2. **实际意义** 如果我们将整个表达式分解来看: ```c (const char **)a // 假设 a 存储了一个地址,并将其视为 const char** 类型 *(const char **)a // 对上述结果进行解引用操作,获取到一个 const char* ``` 这意味着最终返回的是一个指向常量字符数组的指针。通常情况下,这种写法用于处理某些底层内存管理或者跨平台接口调用场景下的类型匹配问题。例如,在 C 标准库中,许多函数接受通用指针类型 `void*` 或者其他形式的指针作为参数,为了确保安全性和一致性,可能需要显式地执行类似的类型转换。[^2] 需要注意的是,虽然可以通过这种方式访问数据,但如果原始数据并非真正的 `const char*` 类型,则可能导致未定义行为。这是因为 C 语言允许程序员绕过一些保护机制来进行低级别的控制,但这同时也增加了潜在的风险。[^3] --- #### 3. **代码示例** 以下是关于此概念的一个简单例子: ```c #include <stdio.h> int main() { char str[] = "hello"; char *ptr = str; // 强制转换并解引用 const char *result = *(const char **)&ptr; printf("%s\n", result); // 输出 hello return 0; } ``` 在这个例子中,`ptr` 最初声明为普通的 `char*` 类型,随后我们利用 `(const char**)&ptr` 把它的地址当作 `const char**` 来对待,最后成功提取出了原本由 `ptr` 所指示的那个字符串首位置的信息。值得注意的是,尽管这里进行了强制转换,但由于源对象确实满足目标类型的语义约束条件,所以不会引发任何运行期错误或异常情况发生。[^4] --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值