c语言 如何记录指针所申请内存空间大小

foolfun 2014-03-15 03:55:21
如何获得指针申请的内存大小,这个值自己肯定是知道的,但是操作系统是如何得知的,有没有什么数据结构保存着这个数值?

#include <stdio.h>

int main(){
char a[] = "hello world!';
char *p = a;
//*(p+20) = 'z';
printf("%s",p);
return 0;
}
如果加上注释掉的代码的话,接下来打印的就是乱码,这里p相当于申请了13个字节的内存空间,p占4个字节,保存的是'h'的地址,那记录p的指向空间的大小的结构是什么。操作系统是怎么知道p所申请的内存空间大小的。

...全文
874 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
勤奋的小游侠 2014-03-16
  • 打赏
  • 举报
回复
引用 16 楼 u012526168 的回复:
[quote=引用 14 楼 lovesmiles 的回复:] [quote=引用 12 楼 u012526168 的回复:] [quote=引用 8 楼 zxcvbnm0014 的回复:] /*(p+20) = 'z'; 字符数组越界了。p指针指向的数据是char型的,p+1就向后移动一个char所占内存的大小。
谢谢回答,但是我问的不是为什么报错,我是想问机器是怎么知道指针所指的对象的长度的[/quote] 你是怎么知道机器知道了指针所指对象的长度?机器完全不知道它所指向对象的长度,只知道指针类型,而这个类型是你声明了的,就这么简单。没有问题了吧?你不信,你随便给指针赋个值完后再访问看看,你的程序肯定死掉,因为程序根本就没有你想像的那样知道它指向了什么,指向的东西有多长。[/quote] 其实我原来是这样想的啊。 char *p = (char*)malloc(sizeof(char)); *(p+0)= 'a'; *(p+1)='b'; *(p+2)='c'; *(p+3)='\0'; printf("%s",p); 结果是abc 符合我的理解。 然而 char a[]= "hello world!"; char *p = a; *(p+12)= 'a'; *(p+13)='b'; *(p+14)='\0'; printf("%s",p); 它的结果我以为是hello world!abc 但是它却崩了,我就开始怀疑之前认为的,这里为什么会崩呢,我以为是机器在某个地方标记了其长度,越界了所以就崩了。 那如果不是这样,这里为什么会崩? 1中的char *p = a;和2中的char *p = (char*)malloc(sizeof(char));的什么区别导致了上述结果呢? [/quote] 这两个是有区别的,malloc 是从堆中分配内存,char a[]是由系统从栈中分配内存,这两块内存位置是不一样的。堆内存访问越界也是可能崩溃的,只不过因为你的堆没有分配其它数据,越界也没有破坏什么,所以你没有碰到崩溃。栈数据的空间是很紧凑的,所以访问越界常常崩溃掉。 这个崩溃和你说的系统知道了指针所指的长度没有关系。
foolfun 2014-03-16
  • 打赏
  • 举报
回复
引用 14 楼 lovesmiles 的回复:
[quote=引用 12 楼 u012526168 的回复:] [quote=引用 8 楼 zxcvbnm0014 的回复:] /*(p+20) = 'z'; 字符数组越界了。p指针指向的数据是char型的,p+1就向后移动一个char所占内存的大小。
谢谢回答,但是我问的不是为什么报错,我是想问机器是怎么知道指针所指的对象的长度的[/quote] 你是怎么知道机器知道了指针所指对象的长度?机器完全不知道它所指向对象的长度,只知道指针类型,而这个类型是你声明了的,就这么简单。没有问题了吧?你不信,你随便给指针赋个值完后再访问看看,你的程序肯定死掉,因为程序根本就没有你想像的那样知道它指向了什么,指向的东西有多长。[/quote] 其实我原来是这样想的啊。 char *p = (char*)malloc(sizeof(char)); *(p+0)= 'a'; *(p+1)='b'; *(p+2)='c'; *(p+3)='\0'; printf("%s",p); 结果是abc 符合我的理解。 然而 char a[]= "hello world!"; char *p = a; *(p+12)= 'a'; *(p+13)='b'; *(p+14)='\0'; printf("%s",p); 它的结果我以为是hello world!abc 但是它却崩了,我就开始怀疑之前认为的,这里为什么会崩呢,我以为是机器在某个地方标记了其长度,越界了所以就崩了。 那如果不是这样,这里为什么会崩? 1中的char *p = a;和2中的char *p = (char*)malloc(sizeof(char));的什么区别导致了上述结果呢?
foolfun 2014-03-16
  • 打赏
  • 举报
回复
引用 17 楼 lovesmiles 的回复:
[quote=引用 16 楼 u012526168 的回复:] [quote=引用 14 楼 lovesmiles 的回复:] [quote=引用 12 楼 u012526168 的回复:] [quote=引用 8 楼 zxcvbnm0014 的回复:] /*(p+20) = 'z'; 字符数组越界了。p指针指向的数据是char型的,p+1就向后移动一个char所占内存的大小。
谢谢回答,但是我问的不是为什么报错,我是想问机器是怎么知道指针所指的对象的长度的[/quote] 你是怎么知道机器知道了指针所指对象的长度?机器完全不知道它所指向对象的长度,只知道指针类型,而这个类型是你声明了的,就这么简单。没有问题了吧?你不信,你随便给指针赋个值完后再访问看看,你的程序肯定死掉,因为程序根本就没有你想像的那样知道它指向了什么,指向的东西有多长。[/quote] 其实我原来是这样想的啊。 char *p = (char*)malloc(sizeof(char)); *(p+0)= 'a'; *(p+1)='b'; *(p+2)='c'; *(p+3)='\0'; printf("%s",p); 结果是abc 符合我的理解。 然而 char a[]= "hello world!"; char *p = a; *(p+12)= 'a'; *(p+13)='b'; *(p+14)='\0'; printf("%s",p); 它的结果我以为是hello world!abc 但是它却崩了,我就开始怀疑之前认为的,这里为什么会崩呢,我以为是机器在某个地方标记了其长度,越界了所以就崩了。 那如果不是这样,这里为什么会崩? 1中的char *p = a;和2中的char *p = (char*)malloc(sizeof(char));的什么区别导致了上述结果呢? [/quote] 这两个是有区别的,malloc 是从堆中分配内存,char a[]是由系统从栈中分配内存,这两块内存位置是不一样的。堆内存访问越界也是可能崩溃的,只不过因为你的堆没有分配其它数据,越界也没有破坏什么,所以你没有碰到崩溃。栈数据的空间是很紧凑的,所以访问越界常常崩溃掉。 这个崩溃和你说的系统知道了指针所指的长度没有关系。[/quote] 太谢谢了。
下巴 2014-03-15
  • 打赏
  • 举报
回复
你要弄清楚指针变量的概念,指针变量存储区域的是一个地址 这个地址是指针所指向内存区域的首地址,而指针所指的数据类型是决定所以想的那块地址的长度。
勤奋的小游侠 2014-03-15
  • 打赏
  • 举报
回复
引用 12 楼 u012526168 的回复:
[quote=引用 8 楼 zxcvbnm0014 的回复:] /*(p+20) = 'z'; 字符数组越界了。p指针指向的数据是char型的,p+1就向后移动一个char所占内存的大小。
谢谢回答,但是我问的不是为什么报错,我是想问机器是怎么知道指针所指的对象的长度的[/quote] 你是怎么知道机器知道了指针所指对象的长度?机器完全不知道它所指向对象的长度,只知道指针类型,而这个类型是你声明了的,就这么简单。没有问题了吧?你不信,你随便给指针赋个值完后再访问看看,你的程序肯定死掉,因为程序根本就没有你想像的那样知道它指向了什么,指向的东西有多长。
foolfun 2014-03-15
  • 打赏
  • 举报
回复
引用 10 楼 baichi4141 的回复:
建议楼主不要空想 稍微学一下汇编语言,看看你写的代码被编译成了哪些机器命令,就知道空想是多么的无价值了 指针指向内存中的一个位置,这个位置存在或不存在,都和指针没关系 如果你申请了一块内存,那么内存管理机制就会记录下分给你的这块内存的大小及位置。如果指针指向的不是你申请的内存,那么这块内存有谁何时怎么样处理,你都不应该猜想。 char a[] = "hello world!";这条语句定义了一个局部数组,而数组在编译后运行时根本不记录其大小,越界修改将导致修改其他数据从而程序运行出错甚至崩溃,这一切都是程序员自作自受,没有任何安全机制供程序员撒娇。
唉,都不好意思说我已经学过汇编了,当时没好好学。 我提这个问题是这样想的:像i386的段描述符八个字节一部分是用于标记段基址的,一部分是标记段限长的,那为什么指针的四个字节全部标记的是所指对象的地址,没有标记所指对象的长度,那机器是如何知道其长度的,是不是内存管理机制有片空间专门用于记录指针长度的? 刚才又做了几个实验,字符指针申请了一个字节的内存空间,但是可以在*(P+7)处给予赋值,确实如你所说。 哈哈我都忘了可以反汇编来看执行过程。 谢谢了。
foolfun 2014-03-15
  • 打赏
  • 举报
回复
引用 8 楼 zxcvbnm0014 的回复:
/*(p+20) = 'z'; 字符数组越界了。p指针指向的数据是char型的,p+1就向后移动一个char所占内存的大小。
谢谢回答,但是我问的不是为什么报错,我是想问机器是怎么知道指针所指的对象的长度的
baichi4141 2014-03-15
  • 打赏
  • 举报
回复
哪怕是同样的申请内存,在不同的内存管理机制中也有不同的实现。 例如MFC的DLL,就是每个DLL分别维持一个内存堆记录,如果你跨DLL进行申请/释放内存,也就是在一个DLL里new另一个DLL里delete,就可能导致该块内存无法被正确释放等后果。 所以不要空想,去学,去查,去理解。没有知识的想象只能成为妄想,任何踏踏实实学东西的人都不该像民科一样。
baichi4141 2014-03-15
  • 打赏
  • 举报
回复
建议楼主不要空想 稍微学一下汇编语言,看看你写的代码被编译成了哪些机器命令,就知道空想是多么的无价值了 指针指向内存中的一个位置,这个位置存在或不存在,都和指针没关系 如果你申请了一块内存,那么内存管理机制就会记录下分给你的这块内存的大小及位置。如果指针指向的不是你申请的内存,那么这块内存有谁何时怎么样处理,你都不应该猜想。 char a[] = "hello world!";这条语句定义了一个局部数组,而数组在编译后运行时根本不记录其大小,越界修改将导致修改其他数据从而程序运行出错甚至崩溃,这一切都是程序员自作自受,没有任何安全机制供程序员撒娇。
foolfun 2014-03-15
  • 打赏
  • 举报
回复
引用 4 楼 derekrose 的回复:
如果是new一个对象 那么内存的大小就是对象的大小 如果new一个数组 那么申请内存的大小就是数组元素的大小乘以数组元素的个数
我想问的是申请的内存大小数值保存在哪?仅有的四个字节32位全部用于记录所指对象的地址了,但是没有记录所指对象占的内存空间大小,那机器如何知道所指的对象的长度呢?应该是一楼说的那样吧。
下巴 2014-03-15
  • 打赏
  • 举报
回复
/*(p+20) = 'z'; 字符数组越界了。p指针指向的数据是char型的,p+1就向后移动一个char所占内存的大小。
foolfun 2014-03-15
  • 打赏
  • 举报
回复
引用 2 楼 xia597289162 的回复:
p保存的是数组a的地址, 当p++的地址超过a 分配的地址,后面的数据是随机值的。p只是以a地址为起始地址。
真不好意思,回复错了,想回复三楼的,回复给你了
foolfun 2014-03-15
  • 打赏
  • 举报
回复
引用 2 楼 xia597289162 的回复:
p保存的是数组a的地址, 当p++的地址超过a 分配的地址,后面的数据是随机值的。p只是以a地址为起始地址。
又试了几个越界的数,不行,将20换成13,14,15...都不行,指针使用前还是要声明内存空间大小的,看来这里就是将a的长度传给了p,越界就可能有问题。
foolfun 2014-03-15
  • 打赏
  • 举报
回复
引用 2 楼 xia597289162 的回复:
p保存的是数组a的地址, 当p++的地址超过a 分配的地址,后面的数据是随机值的。p只是以a地址为起始地址。
确实能运行 可为什么下边这就运行不了呢,char *p = a;不是只给p申请了13字节的内存,P+20不是没有申请吗? int main(){ char a[] = "hello world!"; char *p = a; *(p+12) = 'z'; *(p+13) = 'y'; *(p+14) = '\0'; printf("%s",p); return 0; } int main(){ char a[] = "hello world!"; char *p = a; *(p+12) = 'z'; *(p+13) = '\0'; *(p+14) = 'w'; printf("%s",p); return 0; } 这样也运行不了,把*(p+14) = 'w'注释了就能了
derekrose 2014-03-15
  • 打赏
  • 举报
回复
如果是new一个对象 那么内存的大小就是对象的大小 如果new一个数组 那么申请内存的大小就是数组元素的大小乘以数组元素的个数
常书 2014-03-15
  • 打赏
  • 举报
回复
用DEV验证楼主代码,去掉注释并不会乱码 因为%s是以'\0'作为结束符,楼主写的p+20是'\0'之后的字节,改变了未知地方的内存 字符串定义后,a就是指向"hello world!"字符串的首地址,p=a也只是把p的值赋值为 "hello world!"字符串的首地址 当a赋值为"hello world!"后,地址a为'h',a+1为'e'以此类推,最后一个字节存'\0'共13个 字节,操作系统并没有在其它地方另存一个13,要计算a的空间还是得以'\0'作判断
木子方元 2014-03-15
  • 打赏
  • 举报
回复
p保存的是数组a的地址, 当p++的地址超过a 分配的地址,后面的数据是随机值的。p只是以a地址为起始地址。
羽飞 2014-03-15
  • 打赏
  • 举报
回复
申请内存的时候,内存库会记录下来某个指针对应的内存块大小的

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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