关于c++指针

我爱吃火锅 2010-06-25 09:49:54
#include<iostream>
using namespace std;
void main()
{
int a[]={1,2,3};
int* p=a;
char b[5]={'1','2','3'};
char* q=b;
cout<<p<<endl;
cout<<q<<endl;
cin.get();
}
为什么指针指向普通数字数组和字符数组时,输出指针的值会不同呢?前者输出地址,而后者输出数组值?
还有,假如把b[5]改成b[3],输出地内容又会多出一些汉字,这是为什么呢?谢谢各位。
...全文
373 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
cswuyg 2010-06-27
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 cao_julians 的回复:]
引用 5 楼 wuxupeng999 的回复:
第二个问题,只开辟了3个char的空间,3个空间给'1','2','3'占了,没空间放字符串结束标志:NULL。输出字符串时,约定在遇到NULL时停止输出,在所以在输出字符串的时候,会出错。

================
纠正一个概念:“字符串结束标志:NULL”,尽管“字符串结束标志”和“NULL”的编码都是0,但含义不同,字符串结束……
[/Quote]
字符串结束标志用"\0"表示更规范,这个我同意。我想表达的是ASCII码为0,说成NULL,表述有误。
关于占空间的问题,我觉得不是这样的。测试代码:

#include<iostream>
#include<windows.h>
using namespace std;
int main()
{
char b[3]={'1','2','3'};
(*(BYTE*)&b[3]) = NULL;
cout<<b<<endl;
return 0;
}
/*输出为:
123
Press any key to continue
*/


可以通过动态调试,查看内存,会发现NULL是占一个字节的空间。
sean2023 2010-06-27
  • 打赏
  • 举报
回复
学习!!
smhs001 2010-06-27
  • 打赏
  • 举报
回复
学习了
herman~~ 2010-06-27
  • 打赏
  • 举报
回复
这个是标准IO库对《重载的实现,楼主有兴趣可以看下源码
cao_julians 2010-06-27
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 wuxupeng999 的回复:]
第二个问题,只开辟了3个char的空间,3个空间给'1','2','3'占了,没空间放字符串结束标志:NULL。输出字符串时,约定在遇到NULL时停止输出,在所以在输出字符串的时候,会出错。
[/Quote]
================
纠正一个概念:“字符串结束标志:NULL”,尽管“字符串结束标志”和“NULL”的编码都是0,但含义不同,字符串结束标志正规的表示方式 是'\0',而NULL是无效指针(或称无效地址),另外存储形式也不同,'\0'只占一个字节,而NULL应该是占4个字节。
一些书籍中,用null,nil,NUl等来符号化'\0'实际上使一部分人更糊涂了。
liutengfeigo 2010-06-27
  • 打赏
  • 举报
回复
cao_julians 2010-06-27
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 wuxupeng999 的回复:]
引用 18 楼 cao_julians 的回复:
引用 16 楼 wuxupeng999 的回复:
引用 12 楼 cao_julians 的回复:
引用 11 楼 wuxupeng999 的回复:
引用 10 楼 cao_julians 的回复:
引用 5 楼 wuxupeng999 的回复:……
误矣误矣,你强制类型转换,用BYTE形式访问自然是一个BYTE。
cout<<siz……
[/Quote]
互相启发,共同进步。有许多问题没有遇到就不会去思考,自然就不会有清晰的认识。
cswuyg 2010-06-27
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 wuxupeng999 的回复:]
引用 18 楼 cao_julians 的回复:
引用 16 楼 wuxupeng999 的回复:
引用 12 楼 cao_julians 的回复:
引用 11 楼 wuxupeng999 的回复:
引用 10 楼 cao_julians 的回复:
引用 5 楼 wuxupeng999 的回复:……
误矣误矣,你强制类型转换,用BYTE形式访问自然是一个BYTE。
cout<<siz……
[/Quote]
修改::
确实。是我大意了,我只考虑程序跟内存的对应关系,而没有考虑编译器对程序的修正。那个测试程序赋值为空采用NULL的方式只是为了测试,实际中我不会这么做,虽然编译器会纠正,但那样会产生误解。
至于存储空间,如果把NULL理解为指针,那确实会产生4个字节的空间。如果编译器做了修正,它就不再是NULL、不再是指针,空间自然也就不一定了。

(*(BYTE*)&b[3]) =NULL,之所以写成这么复杂的形式,是为了便于修改,把BYTE修改为DWORD、WORD、double,做不同的测试。
cswuyg 2010-06-27
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 cao_julians 的回复:]
引用 16 楼 wuxupeng999 的回复:
引用 12 楼 cao_julians 的回复:
引用 11 楼 wuxupeng999 的回复:
引用 10 楼 cao_julians 的回复:
引用 5 楼 wuxupeng999 的回复:……
误矣误矣,你强制类型转换,用BYTE形式访问自然是一个BYTE。
cout<<sizeof(NULL)试一试

这个……
编译器把……
[/Quote]
确实。是我大意了,我只考虑程序跟内存的对应关系,而没有考虑编译器对程序的修正。那个测试程序赋值为空采用NULL的方式只是为了测试,实际中我不会这么做,虽然编译器会纠正,但那样会产生误解。
至于存储空间,如果把NULL理解为指针,那确实会产生4个字节的空间。如果编译器做了修正,它就不在是指针了,空间自然也就不一定了。

(*(BYTE*)&b[3]) =NULL,之所以写成这么复杂的形式,是为了便于修改,把BYTE修改为DWORD、WORD、double,做不同的测试。
cao_julians 2010-06-27
  • 打赏
  • 举报
回复
(*(BYTE*)&b[3])

============
&b[3]是char*
(BYTE*)&b[3]是BYTE*,还是char*
(*(BYTE*)&b[3])是BYTE,还是char
cao_julians 2010-06-27
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 wuxupeng999 的回复:]
引用 12 楼 cao_julians 的回复:
引用 11 楼 wuxupeng999 的回复:
引用 10 楼 cao_julians 的回复:
引用 5 楼 wuxupeng999 的回复:……
误矣误矣,你强制类型转换,用BYTE形式访问自然是一个BYTE。
cout<<sizeof(NULL)试一试

这个……
编译器把NULL define为(void *)0。size……
[/Quote]
误矣,
你的代码中:
(*(BYTE*)&b[3]) =NULL
=左边是一个字节还是几个字节?类型是指针还是char?=右边的内容是不是按值转换了才赋值的?
shangyangi 2010-06-27
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 yunyun1886358 的回复:]
1、cout把字符数组当做C风格字符串输出;把普通数字数组名当做一个整数输出。
2、cout把字符数组当做C风格字符串输出,它就会去找结束字符'\0'当做字符串的结束。如果你的字符数组中没有字符'\0',它就会去字符数组后面的内存中寻找字符'\0',就会输出一些不属于字符数组的东西,比如你看到的类似汉字的东西。
[/Quote]

学习 学习
cswuyg 2010-06-27
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 cao_julians 的回复:]
引用 11 楼 wuxupeng999 的回复:
引用 10 楼 cao_julians 的回复:
引用 5 楼 wuxupeng999 的回复:……
误矣误矣,你强制类型转换,用BYTE形式访问自然是一个BYTE。
cout<<sizeof(NULL)试一试
[/Quote]
这个……
编译器把NULL define为(void *)0。sizeof也就是根据(void*)来确定NULL为4个字节,是在编译阶段就确定了的。但是在实际操作的时候,存储NULL所用的未必是4个字节,例如我在11楼的那个程序。
VC下 (*(BYTE*)&b[3]) =NULL;被编译成:
004017C5 . C645 FB 00 MOV BYTE PTR SS:[EBP-5],0
NULL是左值0,它只是一个常数0。就好像数字1、2、3一样,用sizeof获取它们的空间,也是4个字节,但要说它占用了多少空间,只有当它赋给了某个变量之后才有意义。要说NULL占多少空间必须有相应的程序环境,NULL占1个字节的空间,是在11楼的程序环境下的。
所以我觉得用sizeof获得的值是编译阶段获得的值,而真正会用多少字节来存储,要看程序怎么用了。


PS:好像有点偏题了。理解差不多,只不过,cao_julians 是从语法的角度来说,而我是从内存的角度来看的。在G++编译的时候,那样的赋值是会有警告的,VC不会有警告。
cao_julians 2010-06-27
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 cao_julians 的回复:]
引用 11 楼 wuxupeng999 的回复:
引用 10 楼 cao_julians 的回复:
引用 5 楼 wuxupeng999 的回复:
第二个问题,只开辟了3个char的空间,3个空间给'1','2','3'占了,没空间放字符串结束标志:NULL。输出字符串时,约定在遇到NULL时停止输出,在所以在输出字符串的时候,会出错。

================
纠正一个概念……
[/Quote]

'\0'和NULL的区别是类型的区别,不是值的区别:
'\0'是char型
NULL 是void*类型
尽管编码值同样是0,但机内编码一个是一字节,一个是四字节
dcw0402 2010-06-27
  • 打赏
  • 举报
回复
学习 学习
sunzhenchao7 2010-06-27
  • 打赏
  • 举报
回复
看看,呵呵!
cao_julians 2010-06-27
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 wuxupeng999 的回复:]
引用 10 楼 cao_julians 的回复:
引用 5 楼 wuxupeng999 的回复:
第二个问题,只开辟了3个char的空间,3个空间给'1','2','3'占了,没空间放字符串结束标志:NULL。输出字符串时,约定在遇到NULL时停止输出,在所以在输出字符串的时候,会出错。

================
纠正一个概念:“字符串结束标志:NULL”,尽管“字符串结束标志……
[/Quote]
误矣误矣,你强制类型转换,用BYTE形式访问自然是一个BYTE。
cout<<sizeof(NULL)试一试
huzhongtian 2010-06-27
  • 打赏
  • 举报
回复
向4楼学习
「已注销」 2010-06-25
  • 打赏
  • 举报
回复
1、cout把字符数组当做C风格字符串输出;把普通数字数组名当做一个整数输出。
2、将b[5]改成b[3]字符数组中少了‘\0’字符串是以'\0'结尾的, 输出123后没遇到'\0'就会将数组b之后的内存中的内容当作字符串输出直到遇到'\0'或程序崩溃, 而b之后的内存未知所以经常看到乱码.
cswuyg 2010-06-25
  • 打赏
  • 举报
回复
第二个问题,只开辟了3个char的空间,3个空间给'1','2','3'占了,没空间放字符串结束标志:NULL。输出字符串时,约定在遇到NULL时停止输出,在所以在输出字符串的时候,会出错。
加载更多回复(4)
1. C 语言中的指针和内存泄漏 5 2. C语言难点分析整理 10 3. C语言难点 18 4. C/C++实现冒泡排序算法 32 5. C++指针和引用的区别 35 6. const char*, char const*, char*const的区别 36 7. C中可变参数函数实现 38 8. C程序内存中组成部分 41 9. C编程拾粹 42 10. C语言中实现数组的动态增长 44 11. C语言中的位运算 46 12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. C语言复杂表达式的执行步骤 66 16. C语言字符串函数大全 68 17. C语言宏定义技巧 89 18. C语言实现动态数组 100 19. C语言笔试-运算符和表达式 104 20. C语言编程准则之稳定篇 107 21. C语言编程常见问题分析 108 22. C语言编程易犯毛病集合 112 23. C语言缺陷与陷阱(笔记) 119 24. C语言防止缓冲区溢出方法 126 25. C语言高效编程秘籍 128 26. C运算符优先级口诀 133 27. do/while(0)的妙用 134 28. exit()和return()的区别 140 29. exit子程序终止函数与return的差别 141 30. extern与static存储空间矛盾 145 31. PC-Lint与C\C++代码质量 147 32. spirntf函数使用大全 158 33. 二叉树的数据结构 167 34. 位运算应用口诀和实例 170 35. 内存对齐与ANSI C中struct内存布局 173 36. 冒泡和选择排序实现 180 37. 函数指针数组与返回数组指针的函数 186 38. 右左法则- 复杂指针解析 189 39. 回车和换行的区别 192 40. 堆和堆栈的区别 194 41. 堆和堆栈的区别 198 42. 如何写出专业的C头文件 202 43. 打造最快的Hash表 207 44. 指针与数组学习笔记 222 45. 数组不是指针 224 46. 标准C中字符串分割的方法 228 47. 汉诺塔源码 231 48. 洗牌算法 234 49. 深入理解C语言指针的奥秘 236 50. 游戏外挂的编写原理 254 51. 程序实例分析-为什么会陷入死循环 258 52. 空指针究竟指向了内存的哪个地方 260 53. 算术表达式的计算 265 54. 结构体对齐的具体含义 269 55. 连连看AI算法 274 56. 连连看寻路算法的思路 283 57. 重新认识:指向函数的指针 288 58. 链表的源码 291 59. 高质量的子程序 295 60. 高级C语言程序员测试必过的十六道最佳题目+答案详解 297 61. C语言常见错误 320 62. 超强的指针学习笔记 325 63. 程序员之路──关于代码风格 343 64. 指针、结构体、联合体的安全规范 346 65. C指针讲解 352 66. 关于指向指针指针 368 67. C/C++ 误区一:void main() 373 68. C/C++ 误区二:fflush(stdin) 376 69. C/C++ 误区三:强制转换 malloc() 的返回值 380 70. C/C++ 误区四:char c = getchar(); 381 71. C/C++ 误区五:检查 new 的返回值 383 72. C 是 C++ 的子集吗? 384 73. C和C++的区别是什么? 387 74. 无条件循环 388 75. 产生随机数的方法 389 76. 顺序表及其操作 390 77. 单链表的实现及其操作 391 78. 双向链表 395 79. 程序员数据结构笔记 399 80. Hashtable和HashMap的区别 408 81. hash 表学习笔记 410 82. C程序设计常用算法源代码 412 83. C语言有头结点链表的经典实现 419 84. C语言惠通面试题 428 85. C语言常用宏定义 450

64,660

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧