5622|23

384

帖子

0

资源

纯净的硅(高级)

拨开C语言中字符串的那些迷雾(持续更新) [复制链接]

《C和指针》大概很多人都看过吧!最近重新整理了一下笔记,发现可能有很多人跟我在一条起跑线上,为了让你们少走弯路
我决定慢慢的把我的体会和笔记挑一些和大家分享,希望能帮到一些人,如果有错误还请各位共同探讨,一起砸砖。


前面论坛中也有许多人提到过字符串常量,版主也在许多帖中不止一次的提到过;现在我想系统的总结一下:
1.字符串常量:C语言中没有显式的字符串数据类型,字符串是以字符常量的形式出现或者存贮在字符数组中
字符串常量适用于不需要修改的字符串,需要修改的可以使用动态内存分配或字符数组;
C语言中的字符串常量实质是一个指向该字符串第一个字符的指针。
当一个含字符串常量的表达式出现在程序中时,编译器就把这些指定字符的一份拷贝存贮在内存中的某个位置,
并返回一个指向该字符串第一个字符的指针。
有了这一点那么它就可以像指针一样使用了,可以进行指针计算,下标引用,间接访问
"abc"+1;  //指针向后移动一个字节,指向字符b
*“abc“    //输出字符a
"abc"[2]   //输出字符c
"abc"[4]  //数组越界,其值不可预测

至于其中他的
*p="abc";
那就不用说了吧!


再举一例:

void test(int n)
{
       n+=5;
       n/=10;
       printf("%s","**********"+9-n);
}

这个程序比你们以前写的短多了吧!                        

            五楼有更新。。。。。。。。。     

[ 本帖最后由 yaoyong 于 2012-9-23 00:11 编辑 ]
此帖出自编程基础论坛

点评

关于这个,我稍微补充一下: 其实,不能说是把 指定字符 的拷贝存储在内存中。 或者说是,就是把这组字符串常量存储在内存中的静态存储区。 是直接存储,而非拷贝的副本,因为,如果说它是副本,那正本在哪  详情 回复 发表于 2012-9-28 20:58

赞赏

1

查看全部赞赏


回复

160

帖子

0

资源

一粒金砂(中级)

有幸离楼主这么近
关注

点评

谢谢支持,不过最近可能没时间。。。。。。。  详情 回复 发表于 2012-9-26 22:41

回复

17

帖子

0

资源

一粒金砂(初级)

刚好最近在看C专家编程,一个系列的、

点评

那本书我也有,哈哈,看了一半。。。烂尾了  详情 回复 发表于 2012-9-26 22:41

回复

6552

帖子

8

资源

版主

关注!

点评

*(\"abc\"+1)=\'m\'编译的时候没有错误,但是运行的时候就有错误了,怎么解释?错误显示内存不能为write什么的;  详情 回复 发表于 2012-9-27 08:43
个人签名生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰

回复

384

帖子

0

资源

纯净的硅(高级)

前面说过字符串就是一个指针常量,现在请考虑下面这两种形式的初始化:
char *ptstr="abc";   //A声明
char a[ ]="abc";       //B声明
char *a[]="abc";     //C声明
char a[5];
a="abc";          //D声明

char  a[]={"abc"};    //E声明
char  a[5]={"abc"};    //F声明

输出printf("%c ",a[1]);
A声明完全正确,将指针常量赋值给指针变量;
B声明在书中说是不允许的,因为指针并不是字符数据,但我在编译和执行时都通过了;

C明显不行,要用大括号;
D貌似与B是一样的,但根本就无法通过编译;

E,F都能通过编译而且能执行;
在A声明中创建了一个指针变量,用来容纳字符串返回的指针常量,不过请注意,仅仅就是指针常量而已
没有其他的什么东西了,不开辟内存。
请看下面一组赋值:
*("abc"+1)='m';
*(ptstr+1)='m';
*(a+1)='m';

首先要弄清楚左值(l-value)与右值(r-value);
其次是C语言中内存中标识位置(内存)的方式,可以用变量,也可以直接用地址,这就是所谓的间接访问与直接访问;
再者要注意是位置还是值,位置是可以放东西的(里面的东西可以变),而值只能是某个东西不能变;
最后。。。。。。还是老问题,指针与数组的缠绵;

我先写到这里,具体情况且听下回分解;

[ 本帖最后由 yaoyong 于 2012-9-24 22:36 编辑 ]
图片2.bmp

点评

关于这个,俺觉得,正名很重要。 乃们最好要 咬文嚼字,,何为 “定义”,何为“声明”。 声明一般是引用。 定义才是真正涉及内存分配行为的。  详情 回复 发表于 2012-10-1 11:02
*(\"abc\"+1)=\'m\'编译的时候没有错误,但是运行的时候就有错误了,怎么解释?错误显示内存不能为write什么的;  详情 回复 发表于 2012-9-27 08:44

回复

384

帖子

0

资源

纯净的硅(高级)

回复 沙发 幻城 的帖子

谢谢支持,不过最近可能没时间。。。。。。。

回复

384

帖子

0

资源

纯净的硅(高级)

回复 板凳 _本杰明 的帖子

那本书我也有,哈哈,看了一半。。。烂尾了

回复

25

帖子

0

资源

一粒金砂(中级)

回复 4楼 chenzhufly 的帖子

*("abc"+1)='m'编译的时候没有错误,但是运行的时候就有错误了,怎么解释?错误显示内存不能为write什么的;

点评

有的编译器狗屎,比如微软他家的这一系列,连这种这么明显的 使用未开辟内存 的定义 也不报错。 所以,请不要把 编译通过太当一回事。 请注意观察 警告——当然那,如果那些狗屎编译器能提供警告,我也不至于骂  详情 回复 发表于 2012-9-28 21:03

回复

25

帖子

0

资源

一粒金砂(中级)

回复 5楼 yaoyong 的帖子

*("abc"+1)='m'编译的时候没有错误,但是运行的时候就有错误了,怎么解释?错误显示内存不能为write什么的;

点评

当然咯,字符串常量是不允许修改的,如果尝试重写字符串常量标准对此未定义;  详情 回复 发表于 2012-9-27 13:19

回复

384

帖子

0

资源

纯净的硅(高级)

回复 9楼 qq626926200 的帖子

当然咯,字符串常量是不允许修改的,如果尝试重写字符串常量标准对此未定义;

回复

384

帖子

0

资源

纯净的硅(高级)

回复 楼主 yaoyong 的帖子

现在开始解密咯!
先看第一个声明:
指针变量中存贮着字符串指针常量的值,编译器为该变量分配内存,假设一个指针变量占4个字节,那么就分配四个字节给ptstr;
B声明中实际上是提供了为字符数组初始化的简单方式,等价于
char a[4]={'a','b','c',0};
那我们则么区分字符串常量究竟是初始化式的简化还是指针常量呢?这个就简单了,只有在这种初始化时不是指针常量,其他都是。
C声明的是一个字符串数组,数组中存储的是每个字符串所返回的指针常量
D那就是高不成低不就了,这也看一下,那也摸一把,到头来弄得个神马也不是。。。。。。
数组名是一个指针常量,不允许修改;
E,F与B大同小异,实质一样的;

点评

下标访问不仅数组可以有,任何指针都可以,所以数组在使用时并不检查下标是否越界; 对于*(\"abc\"+1)=\'m\';亦可写成“abc”[1]=\'m\';这是对字符串常量的操作,常量是不允许修改的 即使指针常量亦是如此; 而*  详情 回复 发表于 2012-9-28 13:36

回复

384

帖子

0

资源

纯净的硅(高级)

回复 11楼 yaoyong 的帖子

下标访问不仅数组可以有,任何指针都可以,所以数组在使用时并不检查下标是否越界;
对于*("abc"+1)='m';亦可写成“abc”[1]='m';这是对字符串常量的操作,常量是不允许修改的
即使指针常量亦是如此;
而*(ptstr+1)=‘m’;指针的加法表示指针向平移适当的位置,这里是平移一个字节
但是这个位置里面是什么呢?有其他的东西吗?这都是不知道的,ptstr不过是个指针罢了
连房产都没有,还只有个别人的门牌号,就想当房东,那不是抢占地皮吗?如果运气好碰上了好人还好,睁一只眼闭一只眼,万一碰上坏人,直接就挂了你,那就惨咯。。。。
这一点*(a+1)就表现得很好,a可是房东啊,这里都是他的地盘,里面想放什么那当然就随他便咯!

回复

7953

帖子

54

资源

裸片初长成(中级)

回复 楼主 yaoyong 的帖子

编译器就把这些指定字符的一份拷贝存贮在内存中的某个位置

关于这个,我稍微补充一下:

其实,不能说是把 指定字符 的拷贝存储在内存中。
或者说是,就是把这组字符串常量存储在内存中的静态存储区。

是直接存储,而非拷贝的副本,因为,如果说它是副本,那正本在哪呢?说拷贝的时候,会给人一种暗示:这个东西,在内存的其他地方有一份正本。
实际上并非如此。

点评

关于这一点,根据作者的意思我想可能是他把原本写下来的那个字符串当成了本身,然后运行程序的时候就说成拷贝,,,,,, 嗯,确实是把他本身存储在静态存储区。  详情 回复 发表于 2012-10-2 10:45
个人签名

八年一梦,洗尽铅华,重头再来


回复

7953

帖子

54

资源

裸片初长成(中级)

回复 8楼 qq626926200 的帖子

有的编译器狗屎,比如微软他家的这一系列,连这种这么明显的 使用未开辟内存 的定义 也不报错。

所以,请不要把 编译通过太当一回事。
请注意观察 警告——当然那,如果那些狗屎编译器能提供警告,我也不至于骂它狗屎。它就是连警告都不吭声,才狗屎。

这个窗口的意思就是,你(读)写内存有问题,这种情况下,如果你分析明白了,自然就是 写了未开辟的内存空间。
个人签名

八年一梦,洗尽铅华,重头再来


回复

7953

帖子

54

资源

裸片初长成(中级)

回复 5楼 yaoyong 的帖子

关于这个,俺觉得,正名很重要。
乃们最好要 咬文嚼字,,何为 “定义”,何为“声明”。

声明一般是引用。
定义才是真正涉及内存分配行为的。

点评

对对对,关于这一点在关键字extern上表现得尤为突出 这里应该是定义而非声明 多谢斑竹耐心指点,我会更加努力地  详情 回复 发表于 2012-10-2 10:47
个人签名

八年一梦,洗尽铅华,重头再来


回复

6

帖子

0

资源

一粒金砂(初级)

关注

回复

384

帖子

0

资源

纯净的硅(高级)

回复 13楼 辛昕 的帖子

关于这一点,根据作者的意思我想可能是他把原本写下来的那个字符串当成了本身,然后运行程序的时候就说成拷贝,,,,,,
嗯,确实是把他本身存储在静态存储区。

回复

384

帖子

0

资源

纯净的硅(高级)

回复 15楼 辛昕 的帖子

对对对,关于这一点在关键字extern上表现得尤为突出
这里应该是定义而非声明
多谢斑竹耐心指点,我会更加努力地

回复

7953

帖子

54

资源

裸片初长成(中级)

看到楼主提到左值和有值,这的确是相当不错的。
c语法的这一部分其实很复杂而且混淆地厉害,诸如结合性,优先级,让人头疼地想自杀一百次都完全没有问题。

所以一种策略是回避,打不过就要跑。
比如说优先级,加个小括号是不会怀孕的,把一长条表达式分成几条也不会死……
这一部分我想告诉你的一件事情是,,不要自找麻烦~
个人签名

八年一梦,洗尽铅华,重头再来


回复

7953

帖子

54

资源

裸片初长成(中级)

看到楼主提到左值和有值,这的确是相当不错的。
c语法的这一部分其实很复杂而且混淆地厉害,诸如结合性,优先级,让人头疼地想自杀一百次都完全没有问题。

所以一种策略是回避,打不过就要跑。
比如说优先级,加个小括号是不会怀孕的,把一长条表达式分成几条也不会死……
这一部分我想告诉你的一件事情是,,不要自找麻烦~
个人签名

八年一梦,洗尽铅华,重头再来


回复
您需要登录后才可以回帖 登录 | 注册

最新文章 更多>>
    关闭
    站长推荐上一条 1/7 下一条

    About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

    站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

    北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

    电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved
    快速回复 返回顶部 返回列表