C语言—字符串数组与指针的区别
作者:追风剑情 发布于:2019-10-15 21:17 分类:C
const char ar1[29] = "this is a char array.";
const char *pt1 = "this is a char array.";
数组形式(ar1[])在计算机的内存中分配为一个内含22个元素的数组(每个元素对应一个字符,还加上一个末尾的空字符‘\0’),每个元素被初始化为字符串字面量对应的字符。通常,字符串都作为可执行文件的一部分储存在数据段中。当把程序载入内存时,也载入了程序中的字符串。字符串储存在静态存储区(static memory)中。但是,程序在开始运行时才会为该数组分配内存。此时,才将字符串拷贝到数组中。注意,此时字符串有两个副本。一个是在静态内存中的字符串字面量,另一个是储存在ar1数组中的字符串。
此后,编译器便把数组名ar1识别为该数组首元素地址(&ar1[0])的别名。这里关键要理解,在数组形式中,ar1是地址常量。不能更改ar1,如果改变了ar1,则意味着改变了数组的存储位置(即地址)。可以进行类似ar1+1这样的操作,标识数组的下一个元素。但是不允许进行++ar1这样的操作。递增运算符只能用于变量名前(或概括地说,只能用于可修改的左值),不能用于常量。
指针形式(*pt1)也使得编译器为字符串在静态存储区预留22个元素的空间。另外,一旦开始执行程序,它会为指针变量pt1留出一个储存位置,并把字符串的地址储存在指针变量中。该变量最初指向该字符串的首字符,但是它的值可以改变。因此,可以使用递增运算符。例如,++pt1将指向第2个字符(h)。
字符串字面量被视为const数据。由于pt1指向这个const数据,所以应该把pt1声明为指向const数据的指针。这意味着不能用pt1改变它所指向的数据,但是仍然可以改变pt1的值(即,pt1指向的位置)。如果把一个字符串字面量拷贝给一个数组,就可以随意改变数据,除非把数组声明为const。
总之,初始化数组把静态存储区的字符串拷贝到数组中,而初始化指针只把字符串的地址拷贝给指针。
示例
//Visual Studio中加上这句才可以使用scanf() //否则只能使用scanf_s() #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdbool.h> #define MSG "I'm special" //argc: 参数个数 argv[]: 参数数组 int main(int argc, char *argv[]) { char ar[] = MSG; const char *pt = MSG; printf("address of \"I'm special\": %p \n", "I'm special"); printf(" address ar: %p\n", ar); printf(" address pt: %p\n", pt); printf("address of MSG: %p\n", MSG); printf("address of \"I'm special\": %p \n", "I'm special"); system("pause"); return 0; }
运行测试
打印结果说明:
1、pt和MSG地址相同,说明pt指向静态存储区的I'm special
2、ar和MSG地址不同,说明ar存储的是I'm special的副本
3、I’m special字符串在程序中出现了多次,但编译器只使用了一个存储位置(因使用的编译器而异)
4、静态数据使用的内存与ar使用的动态内存不同,不仅值不同,特定编译器甚至使用不同的位数表示两种内存
示例二:数组与指针的区别
//Visual Studio中加上这句才可以使用scanf() //否则只能使用scanf_s() #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdbool.h> //argc: 参数个数 argv[]: 参数数组 int main(int argc, char *argv[]) { //数组名heart是常量 char heart[] = "I love Tillie!"; //指针名heard是变量 const char *head = "I love Millie!"; //两者都可以使用数组表示法 for (int i = 0; i < 6; i++) putchar(heart[i]); putchar('\n'); for (int i = 0; i < 6; i++) putchar(head[i]); putchar('\n'); //两者都能进行指针加法操作 for (int i = 0; i < 6; i++) putchar(*(heart + i)); putchar('\n'); for (int i = 0; i < 6; i++) putchar(*(head + i)); putchar('\n'); //只有指针表示法可以进行递增操作 while (*(head) != '\0') //在字符串末尾处停止 putchar(*(head++));//打印字符,指针指向下一个位置 putchar('\n'); //可以将数组赋给指针 //head = heart; //不能将指针赋给数组,因为赋值运算的左侧必须是变量, //或者是可修改的左值,如*pt_int。 //heart = head;//非法 //两者都可改变数组中元素的信息 //下面两句等效 heart[7] = 'M'; *(heart + 7) = 'M'; //数组的元素是变量(除非数组被声明为const),但是数组名不是变量。 //未使用const限定符的指针初始化 char * word = "frame"; //编译器可能允许这样做,但是对当前的C标准而言,这样的行为是 //未定义的。因为指针指向的是存储在静态区中的原始字符串,可能 //会影响其他使用了这个字符串的地方。 //word[1] = 'l';//未定义的行为,可能导致程序异常 //因此,建议在把指针初始化为字符串字面量时使用const限定符 const char * p1 = "Klingon"; //推荐用法 //然而,把非const数组初始化为字符串字面量却不会导致类似问题。 //因为数组获得的是原始字符串的副本。 system("pause"); return 0; }
运行测试
示例:字符串数组
//Visual Studio中加上这句才可以使用scanf() //否则只能使用scanf_s() #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdbool.h> #define SLEN 40 #define LIM 5 //argc: 参数个数 argv[]: 参数数组 int main(int argc, char *argv[]) { //内含5个指针的数组 //指针所指向的字符串字面量储存在静态内存中 const char *mytalents[LIM] = { "Adding numbers swiftly", "Multiplying accurately", "Stashing data", "Following instructions to the letter", "Understanding the Clanguage" }; //内含5个数组的数组,每个数组内含40个char类型的值,共占200字节。 //子数组储存的是字符串字面量的副本 char yourtalents[LIM][SLEN] = { "Walking in a straight line", "Sleeping", "Watching television", "Mailing letters", "Reading email" }; int i; puts("Let's compare talents."); printf("%-36s %-25s\n", "My Talents", "Your Talents"); for (i = 0; i < LIM; i++) printf("%-36s %-25s\n", mytalents[i], yourtalents[i]); printf("\nsizeof mytalents: %zd, sizeof yourtalents: %zd\n", sizeof(mytalents), sizeof(yourtalents)); /* 总之,如果不需要更改字符串字面量,推荐使用指针表示法(效率高). 如果需要更改,则使用数组表示法。 */ system("pause"); return 0; }
示例:指针和字符串
//Visual Studio中加上这句才可以使用scanf() //否则只能使用scanf_s() #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdbool.h> //argc: 参数个数 argv[]: 参数数组 int main(int argc, char *argv[]) { const char * mesg = "Don't be a fool!"; const char * copy; //让copy指向mesg指向的字符串地址 copy = mesg; printf("%s\n", copy); //如果编译器不识别%p,用%u或%lu代替%p printf("mesg = %s; &mesg = %p; value = %p\n", mesg, &mesg, mesg); printf("copy = %s; © = %p; value = %p\n", copy, ©, copy); system("pause"); return 0; }
标签: C语言
日历
最新文章
随机文章
热门文章
分类
存档
- 2024年11月(3)
- 2024年10月(5)
- 2024年9月(3)
- 2024年8月(3)
- 2024年7月(11)
- 2024年6月(3)
- 2024年5月(9)
- 2024年4月(10)
- 2024年3月(11)
- 2024年2月(24)
- 2024年1月(12)
- 2023年12月(3)
- 2023年11月(9)
- 2023年10月(7)
- 2023年9月(2)
- 2023年8月(7)
- 2023年7月(9)
- 2023年6月(6)
- 2023年5月(7)
- 2023年4月(11)
- 2023年3月(6)
- 2023年2月(11)
- 2023年1月(8)
- 2022年12月(2)
- 2022年11月(4)
- 2022年10月(10)
- 2022年9月(2)
- 2022年8月(13)
- 2022年7月(7)
- 2022年6月(11)
- 2022年5月(18)
- 2022年4月(29)
- 2022年3月(5)
- 2022年2月(6)
- 2022年1月(8)
- 2021年12月(5)
- 2021年11月(3)
- 2021年10月(4)
- 2021年9月(9)
- 2021年8月(14)
- 2021年7月(8)
- 2021年6月(5)
- 2021年5月(2)
- 2021年4月(3)
- 2021年3月(7)
- 2021年2月(2)
- 2021年1月(8)
- 2020年12月(7)
- 2020年11月(2)
- 2020年10月(6)
- 2020年9月(9)
- 2020年8月(10)
- 2020年7月(9)
- 2020年6月(18)
- 2020年5月(4)
- 2020年4月(25)
- 2020年3月(38)
- 2020年1月(21)
- 2019年12月(13)
- 2019年11月(29)
- 2019年10月(44)
- 2019年9月(17)
- 2019年8月(18)
- 2019年7月(25)
- 2019年6月(25)
- 2019年5月(17)
- 2019年4月(10)
- 2019年3月(36)
- 2019年2月(35)
- 2019年1月(28)
- 2018年12月(30)
- 2018年11月(22)
- 2018年10月(4)
- 2018年9月(7)
- 2018年8月(13)
- 2018年7月(13)
- 2018年6月(6)
- 2018年5月(5)
- 2018年4月(13)
- 2018年3月(5)
- 2018年2月(3)
- 2018年1月(8)
- 2017年12月(35)
- 2017年11月(17)
- 2017年10月(16)
- 2017年9月(17)
- 2017年8月(20)
- 2017年7月(34)
- 2017年6月(17)
- 2017年5月(15)
- 2017年4月(32)
- 2017年3月(8)
- 2017年2月(2)
- 2017年1月(5)
- 2016年12月(14)
- 2016年11月(26)
- 2016年10月(12)
- 2016年9月(25)
- 2016年8月(32)
- 2016年7月(14)
- 2016年6月(21)
- 2016年5月(17)
- 2016年4月(13)
- 2016年3月(8)
- 2016年2月(8)
- 2016年1月(18)
- 2015年12月(13)
- 2015年11月(15)
- 2015年10月(12)
- 2015年9月(18)
- 2015年8月(21)
- 2015年7月(35)
- 2015年6月(13)
- 2015年5月(9)
- 2015年4月(4)
- 2015年3月(5)
- 2015年2月(4)
- 2015年1月(13)
- 2014年12月(7)
- 2014年11月(5)
- 2014年10月(4)
- 2014年9月(8)
- 2014年8月(16)
- 2014年7月(26)
- 2014年6月(22)
- 2014年5月(28)
- 2014年4月(15)
友情链接
- Unity官网
- Unity圣典
- Unity在线手册
- Unity中文手册(圣典)
- Unity官方中文论坛
- Unity游戏蛮牛用户文档
- Unity下载存档
- Unity引擎源码下载
- Unity服务
- Unity Ads
- wiki.unity3d
- Visual Studio Code官网
- SenseAR开发文档
- MSDN
- C# 参考
- C# 编程指南
- .NET Framework类库
- .NET 文档
- .NET 开发
- WPF官方文档
- uLua
- xLua
- SharpZipLib
- Protobuf-net
- Protobuf.js
- OpenSSL
- OPEN CASCADE
- JSON
- MessagePack
- C在线工具
- 游戏蛮牛
- GreenVPN
- 聚合数据
- 热云
- 融云
- 腾讯云
- 腾讯开放平台
- 腾讯游戏服务
- 腾讯游戏开发者平台
- 腾讯课堂
- 微信开放平台
- 腾讯实时音视频
- 腾讯即时通信IM
- 微信公众平台技术文档
- 白鹭引擎官网
- 白鹭引擎开放平台
- 白鹭引擎开发文档
- FairyGUI编辑器
- PureMVC-TypeScript
- 讯飞开放平台
- 亲加通讯云
- Cygwin
- Mono开发者联盟
- Scut游戏服务器引擎
- KBEngine游戏服务器引擎
- Photon游戏服务器引擎
- 码云
- SharpSvn
- 腾讯bugly
- 4399原创平台
- 开源中国
- Firebase
- Firebase-Admob-Unity
- google-services-unity
- Firebase SDK for Unity
- Google-Firebase-SDK
- AppsFlyer SDK
- android-repository
- CQASO
- Facebook开发者平台
- gradle下载
- GradleBuildTool下载
- Android Developers
- Google中国开发者
- AndroidDevTools
- Android社区
- Android开发工具
- Google Play Games Services
- Google商店
- Google APIs for Android
- 金钱豹VPN
- TouchSense SDK
- MakeHuman
- Online RSA Key Converter
- Windows UWP应用
- Visual Studio For Unity
- Open CASCADE Technology
- 慕课网
- 阿里云服务器ECS
- 在线免费文字转语音系统
- AI Studio
- 网云穿
- 百度网盘开放平台
- 迅捷画图
- 菜鸟工具
- [CSDN] 程序员研修院
- 华为人脸识别
- 百度AR导航导览SDK
- 海康威视官网
- 海康开放平台
- 海康SDK下载
- git download
交流QQ群
-
Flash游戏设计: 86184192
Unity游戏设计: 171855449
游戏设计订阅号