(笔记)char * p与 char p[ ] 的区别

C语言字符串详解
本文深入解析C语言中字符串的处理方式,包括不同声明方式的区别、内存分配位置的影响及最佳实践建议。

简单的代码:

#include <stdio.h>
int main()
{
    char * a = "abcdef";
    char * b = "abcdef";
    char c[] = "abcdef";
    char d[] = {'a','b','c','d','e','f'};

    printf("%10d\n",sizeof(a));
    printf("%10d\n",sizeof(b));
    printf("%10d\n",sizeof(c));
    printf("%10d\n",sizeof(d));

    printf("%10x%10x\n",a,b);
    return 0;
}
//运行结果:
//         4
//         4
//         7
//         6
//   8048520   8048520

分析:

一. 从声明的对象

char c[ ] = “abcdef”;
是声明一个字符数组并对其初始化,可以理解为 char c[ ]= {‘a’,’b’,’c’,’d’,’e’,’f’,’\0’};
所以c[ ] 和 d[ ]区别在于数组结尾没有‘\0’。所以sizeof(c)为7,sizeof(d)为6。

char * a = “abcdef”语句
是声明一个指针,并对指针赋值。相当于:

 char * a;       // 所以sizeof(a)为4(32位机器)
 a = "abcdef";   // p指向字符串"abcdef"的首地址

二. 存放的位置

char c[ ] = "abcdef";    //作为局部变量存放在 栈区
char * a = "abcdef";     //"abcdef"是存放在静态代码块中的,是全局的, a仅仅是一个指针指向"abcdef"
                         //所以printf("%10x%10x\n",a,b);的结果是相同的
                         //相当于:const char * a = "abcdef";

它跟我们用static修饰的变量存放的位置是一样的
char c[] = “abcdef”; 的”abcdef”是存放在静态代码块中的

例子:

#include "stdio.h"
char * get_string_1()
{
    char p[] = "hello world!";
    return p;
}

char * get_string_2()
{
    char * p = "hello world!";
    return p;
}

int main()
{
    char * p;
    p = get_string_1();
    printf("get_string_1:%s/n",p);

    p = get_string_2();
    printf("get_string_2:%s\n",p);
    return 0;
}

输出:
get_string_1:(乱码或者没有输出),Linux下没有任何输出
get_string_2:hello world!
为什么会这样?

原因:C函数执行完之后对栈区进行清除操作,对静态数据区和堆则没有,
因此问题也就不难解释了,get_string_1()函数执行完就释放了栈区内存,
所以根本就不存在存有”hello world!”声明时的内存,也就不可能有所输出。

三. 写成char * p = "abcdef";到底合不合法?能不能这样写?

这是一个历史问题,在const关键字被引入C语言之前,这样写是合法的,而且存在了很长的一段时间,大量的代码在此期间运用了这种写法,新版C语言为了兼容,故允许这样写,但最好不要这样,因为这种写法终会被淘汰,说不定哪天你的代码用了新版的编译器,然后莫名的出了问题,要找这个BUG估计不是一件容易的事。

       char * p = "abcdef";  // p是指针,指向字符串常量"abcdef"

所以现在最好写成:

       const char * p = "abcdef";
    或者
        char p[] = "abcdef";
<think>好的,我需要帮助用户解决如何给类型为const char**的变量赋值的问题。用户提到使用C语言,并且需要示例代码。首先,我得回顾一下用户提供的引用内容,看看有没有相关的信息。 根据引用[2],C语言中const char**类型的变量赋值存在一些问题,因为C的类型系统不允许直接将char**赋值给const char**,否则编译器会发出警告。这是因为C的const限定符在双重指针的情况下有严格的类型检查,防止潜在的修改风险。比如,如果允许char**赋值给const char**,那么可能通过间接修改导致原本声明为const的数据被改变,这是不安全的。 然后,引用[3]中的笔记提到char*、const char*char[]的区别,可能涉及到如何正确转换这些类型。而引用[4]中的例子展示了当尝试将const char*赋值给char*时出现的错误,说明类型转换必须显式且符合const的规则。 用户的问题是给const char**赋值,所以需要明确正确的赋值方法。可能的解决方案包括显式类型转换,或者确保源指针类型目标类型兼容。例如,如果有一个const char*数组,那么其地址可以赋给const char**。但如果是非const的char*数组,直接赋值会导致类型不匹配,需要强制转换,但这样做可能不安全。 另外,引用[2]还提到C++如何解决这个问题,但用户明确要求C语言,所以需要专注于C的方法。可能需要分步骤说明,先声明合适的源数组,再赋值给const char**,同时处理类型转换的问题。 接下来,我需要验证这些思路是否正确。比如,声明一个const char*数组,然后将其地址赋给const char**变量,这应该是合法的。如果是非const的数组,则需要强制转换,但这样做可能会有风险,需要警告用户注意。 最后,需要给出示例代码,展示正确和错误的案例,以及如何避免编译器警告。同时,解释类型安全的重要性,防止用户误用导致未定义行为。</think>在C语言中给$const\ char**$类型变量赋值需要特别注意类型安全性,这涉及两层指针的$const$限定关系。以下是具体实现方法和注意事项: ### 正确赋值方法 1. **直接匹配类型**(最安全方式) ```c const char* src[] = {"Hello", "World"}; const char** ppc = src; // 直接赋值类型完全匹配 ``` 2. **强制类型转换**(存在安全隐患) ```c char* arr[] = {"A", "B"}; const char** ppc = (const char**)arr; // 强制转换消警告 ``` ### 错误示例分析 ```c char* arr[] = {"C", "D"}; const char** ppc = arr; // 产生编译警告 ``` 编译器会提示:`warning: assignment discards 'const' qualifier from pointer target type`,这是C语言类型系统的保护机制[^2]。 ### 安全赋值原理 当需要给$const\ char**$赋值时,必须确保: 1. 源指针数组的每个元素本身是$const\ char*$类型 2. 若源数组元素不是$const$,必须显式添加限定符 ### 完整示例代码 ```c #include <stdio.h> int main() { // 正确方式1:完全匹配类型 const char* str1[] = {"Apple", "Banana"}; const char** ppc1 = str1; printf("%s %s\n", ppc1[0], ppc1[1]); // 正确方式2:带显式转换的非const数组 char* str2[] = {"Cat", "Dog"}; const char** ppc2 = (const char**)str2; printf("%s %s\n", ppc2[0], ppc2[1]); return 0; } ``` ### 注意事项 1. 强制转换会绕过编译器检查,可能导致未定义行为 2. 修改通过强制转换得到的$ppc2[0][0]$会引发段错误 3. 推荐优先使用完全$const$限定的原始数组[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值