0

0

字符数组和字符指针

高洛峰

高洛峰

发布时间:2016-12-12 17:16:11

|

1378人浏览过

|

来源于php中文网

原创

问题1:

字符数组名可以作为左值吗?当然不行

比如 

char str[20] = {'h','e','l','l','o',' ','w','o','r','l','d'};

str++;

不可以这么干,因为字符数组名是一个常量指针,也就是是一个const char*

#include 

int main()
{
    char str[20] = {'h','e','l','l','o',' ','w','o','r','l','d'};
    printf("sizeof(str): %d\n",sizeof(str));
    printf("str: %s\n",str);
    str = str + 1;  //error
    return 0;
}

运行结果如下:

字符串数组

当数组名为左值时,它的类型是字符数组;当数组名为右值时,它的数据类型是字符指针。

#include 
#include 
int main(void)
{
    char buf[10];
    char *p= “afdal”;
    buf = p;  //将一个char* 赋给一个char[10],类型不一样,必然不成功
    printf(“the buf is:%s\n”,buf);
    return 0;
}

问题2:

字符数组如何进行初始化?

#include 

int main()
{
    char ptr[20] = "hello world";  //success
    char str[20] = {'h','e','l','l','o',' ','w','o','r','l','d'};  //success
    char ctr[20];
    ctr = "hello world";  // error: incompatible types when assigning to type ‘char[20]’ from type ‘char *’
    return 0;
}

在给字符数组初始化的时候,会自动在字符数组的结尾加上'\0'

#include 

int main()
{
    char str[20] = {'h','e','l','l','o',' ','w','o','r','l','d'};
    printf("sizeof(str): %d\n",sizeof(str));
    printf("str: %s\n",str);
    int i = 0;
    while(*(str + i) != '\0')  //判断是否加上'\0'
    {
        printf("%c\n",*( str + i++));
    }
    return 0;
}

运行结果如下:

字符串数组

问题3:

字符数组越界访问能编译通过吗?

字符数组越界访问编译可以通过,没有报错,这样会出现很多的问题

#include 

int main()
{
    char str[12] = {'h','e','l','l','o',' ','w','o','r','l','d'};
    printf("%c\n",str[100]);
    return 0;
}

字符串数组

打印为空

问题4:

字符数组和字符指针又有什么区别呢?

首先在内存的中位置不同,字符数组保存的字符串存放在内存的栈中,而字符指针指向的字符串保存在内存的静态存储区中。

其次字符数组保存的字符串属于字符串变量,可以被修改,而字符指针指向的字符串是属于字符串常量,不能被修改。

#include 

int main()
{
    char str[12] = {'h','e','l','l','o',' ','w','o','r','l','d'};
    char* ptr = "hello world";
    str[0] = 'f';
    ptr[0] = 'f';  //将字符指针指向的字符串修改,将出现段错误,因为该内存地址只读,因为该字符串属于常量
    return 0;
}

运行结果:

字符串数组

段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址、访问了系统保护的内存地址、访问了只读的内存地址等等情况。

#include 

int main()
{
    char* ptr = "hello world";
    ptr[11] = '!';  //往常量字符串末尾添加字符,相当于连接两个字符串,出错
    ptr[12] = '\0';
    return 0;
}

这样也会出现段错误。

问题5:

字符指针是不是和字符数组名都是指针常量呢?

不是,字符指针,可以改变它的指向,也就是可以为左值。可以将一个字符指针指向一个字符串常量后又指向另外一个字符串常量。字符指针在为初始化之前,他是一个未定义的值,将指向任何可能的地方,所以在使用字符指针时一定要注意初始化。

#include 

int main()
{
    char* ptr;
    printf("ptr: %c\n",*ptr);
    return 0;
}

运行结果:

编译可以通过,但是ptr指向的内存地址是任意的

当然也可以将一个字符指针指向一个字符数组。

#include 

int main()
{
    char str[12] = {'h','e','l','l','o',' ','w','o','r','l','d'};
    char* ptr = str;
    printf("ptr: %s\n",ptr);
    return 0;
}

运行结果:

字符串数组

I-Shop购物系统
I-Shop购物系统

部分功能简介:商品收藏夹功能热门商品最新商品分级价格功能自选风格打印结算页面内部短信箱商品评论增加上一商品,下一商品功能增强商家提示功能友情链接用户在线统计用户来访统计用户来访信息用户积分功能广告设置用户组分类邮件系统后台实现更新用户数据系统图片设置模板管理CSS风格管理申诉内容过滤功能用户注册过滤特征字符IP库管理及来访限制及管理压缩,恢复,备份数据库功能上传文件管理商品类别管理商品添加/修改/

下载

问题6:

如果一个字符指针指向一个堆中动态内存。那么我们如何初始化该内存中的值?

#include 
#include 

int main()
{ 
    char* str = (char*)malloc(sizeof(char)*20);
    printf("str:%p\n",str);     //str在堆中内存首地址
    str = "hello world";
    printf("str:%p\n",str);    //str在静态存储区内存首地址
    char* ptr = "I love you";
    printf("ptr:%p\n",ptr);    //str在静态存储区内存首地址
    return 0;
}

运行结果如下:

字符串数组

很明显前后的地址不一样,前一个指向堆中的内存的地址,而后一个指向了静态存储区中的内存的地址。我本以为我通过上述方式进行初始化str的时候,我可以将堆中内存进行初始化,我发现我错了,字符指针将被重新指向。但是我想如果我们将str声明为const呢?那将会出现什么样的结果呢?

#include 
#include 

int main()
{ 
    const char* str = (char*)malloc(sizeof(char)*20);  //我以为const将修饰str,使得str不能再作为左值而出现,我错了,const修饰的是由str指向的字符串,
    printf("str:%p\n",str);                            //该字符串不能再被修改
    str = "hello world";
    printf("str:%p\n",str);  
    return 0;
}

运行结果:

字符串数组

如果我们将上述的代码做如下修改,程序还能编译通过吗?

#include 
#include 

int main()
{ 
    const char* str = (char*)malloc(sizeof(char)*20);
    printf("str:%p\n",str);
    str[0] = 'h';    //这种赋值才是对str原来所指向的堆中的内存的赋值,编译不过,因为str指向的堆中的内存是只读的。
    str = "hello world";     
    printf("str:%p\n",str);
    return 0;
}

运行结果如下:

字符串数组

上述就引发了我思考为什么const修饰的是str指向的字符串,而不是str本身呢?

原来,char* const str才是真正的修饰str本身,使得str为只读的,不能再被修改,也就是重新指向其他内存地址。而const char* str 和 char const* str 的意义是一致的,都是修饰的是*str。

#include 
#include 

int main()
{ 
    char* const str = (char*)malloc(sizeof(char)*20);
    printf("str:%p\n",str);
    str[0] = 'h'; 
    str = "hello world";      //变量str被重新指向,error,编译不过
    printf("str:%p\n",str);
    return 0;
}

运行结果如下:

字符串数组

那么我们又该如何初始化一个字符指针指向的内存呢?

其实我们可以很清楚的分析,如果str是一个字符指针,也就是一个变量,变量是可以被重新赋值的,而每一个字符串本身是有一个地址的,str = “hello world”,必然就是改变了str的值,使得str保存着"hello world"的内存首地址,而一旦你将str = "I love you",必然str将保存这"I love you"的内存首地址,这都是毋庸置疑的。

#include 

int main()
{
    printf("hello world:%p\n","hello world");   //将打印出"hello world"的内存地址
    printf("I love you:%p\n","I love you");    //将打印出"I love you"的内存地址
    return 0; 
}

运行如下:

字符串数组

下面我得回到这样一个问题?

str 和 *str的区别,很明显,str是一个指针,而*str是str指向的内存的存放的值,既然我们想改变str指向内存中的值,既*str的值,那么为何不将*str作为左值,来初始化str所指向内存的值呢?而*str 不就是 str[0]吗?所以很明显了。上述问题:那么我们又该如何初始化一个字符指针指向的内存呢?当然这个仅限于字符指针指向的是由mlloc分配的堆中的内存以及字符数组指向的栈中的内存。而字符指针如果指向字符常量,不可修改字符指针指向的内存的值,因为字符常量是只读的。

#include 
#include 

int main()
{ 
    char* const str = (char*)malloc(sizeof(char)*20);
    printf("str:%p\n",str);
    str[0] = 'A';     //数组下标型赋值
    *(str + 1) = 'l';  //指针++型赋值
    str[2] = 'e',
    *(str + 3) = 'x';
    printf("str:%s\n",str);  
    printf("str:%p\n",str);
    return 0;
}

运行如下:

字符串数组

#include 
#include 
int main()
{ 
    char str[20]; 
    printf("str:%p\n",str);
    str[0] = 'A'; 
    *(str + 1) = 'l';
    str[2] = 'e',
    *(str + 3) = 'x';
    //str[4] = '\0';  //当我们没有手动给字符串结尾附上'\0'
    printf("str:%s\n",str);
    printf("str:%p\n",str);
    return 0; 
}

运行如下:

字符串数组

上述的运行结果说明上述程序并没有自动给字符串结尾附上'\0',对于字符数组除非这样赋值,str[20] = "hello world",不然你就得手动给字符串附上字符串结尾'\0'。

#include 
#include 

int main()
{ 
    char str[20]; 
    printf("str:%p\n",str);
    str[0] = 'A'; 
    *(str + 1) = 'l';
    str[2] = 'e',
    *(str + 3) = 'x';
    str[4] = '\0';
    printf("str:%s\n",str);
    printf("str:%p\n",str);
    return 0; 
}   
~

运行结果:

字符串数组

附上一段我关于memcpy()和memmove()的代码的实现。

#include 
#include 

void mem_copy(char* const dest, const char* const src)
{
    for(int i = 0; *(src + i) != '\0'; i++)
        *(dest + i) = *(src + i);
}

void mem_move(char* const dest, const char* const src)
{
    int i = 0;
    while(*(src + i) != '\0')
        i++;
    for(; i != -1; i--)
        *(dest + i) = *(src + i);
}

int main()
{
    char* src = "hello world";
    char* const dest1 = (char*)malloc(sizeof(char) * 20);
    char dest2[20];
    mem_copy(dest1,src);
    mem_move(dest2,src);
    printf("dest1:%s\n",dest1);
    printf("dest2:%s\n",dest2);
    return 0;
}

当我们需要将内存的中的某一地址段的内容拷贝到内存中另一地址段中,以上是将字符串常量区的内容拷贝到堆中和栈中,我们可以看到我分别使用了malloc和字符数组,当然我们得考虑可能在拷贝的过程中会有地址段重叠的问题,重叠该怎么拷贝,解决方案很简单,就是从尾向前拷贝,即可。

运行结果如下:

字符串数组

以上是我对c语言中字符串操作的一些理解

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
go语言 注释编码
go语言 注释编码

本专题整合了go语言注释、注释规范等等内容,阅读专题下面的文章了解更多详细内容。

32

2026.01.31

go语言 math包
go语言 math包

本专题整合了go语言math包相关内容,阅读专题下面的文章了解更多详细内容。

23

2026.01.31

go语言输入函数
go语言输入函数

本专题整合了go语言输入相关教程内容,阅读专题下面的文章了解更多详细内容。

16

2026.01.31

golang 循环遍历
golang 循环遍历

本专题整合了golang循环遍历相关教程,阅读专题下面的文章了解更多详细内容。

5

2026.01.31

Golang人工智能合集
Golang人工智能合集

本专题整合了Golang人工智能相关内容,阅读专题下面的文章了解更多详细内容。

6

2026.01.31

2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

268

2026.01.31

高干文在线阅读网站大全
高干文在线阅读网站大全

汇集热门1v1高干文免费阅读资源,涵盖都市言情、京味大院、军旅高干等经典题材,情节紧凑、人物鲜明。阅读专题下面的文章了解更多详细内容。

195

2026.01.31

无需付费的漫画app大全
无需付费的漫画app大全

想找真正免费又无套路的漫画App?本合集精选多款永久免费、资源丰富、无广告干扰的优质漫画应用,涵盖国漫、日漫、韩漫及经典老番,满足各类阅读需求。阅读专题下面的文章了解更多详细内容。

170

2026.01.31

漫画免费在线观看地址大全
漫画免费在线观看地址大全

想找免费又资源丰富的漫画网站?本合集精选2025-2026年热门平台,涵盖国漫、日漫、韩漫等多类型作品,支持高清流畅阅读与离线缓存。阅读专题下面的文章了解更多详细内容。

85

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Swoft2.x速学之http api篇课程
Swoft2.x速学之http api篇课程

共16课时 | 0.9万人学习

php初学者入门课程
php初学者入门课程

共10课时 | 0.6万人学习

PHP基础入门课程
PHP基础入门课程

共33课时 | 2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号