user-0 提问: c语言 如何记录指针所申请内存空间大小

回复:
user: user-1
content: 引用 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[]是由系统从栈中分配内存，这两块内存位置是不一样的。堆内存访问越界也是可能崩溃的，只不过因为你的堆没有分配其它数据，越界也没有破坏什么，所以你没有碰到崩溃。栈数据的空间是很紧凑的，所以访问越界常常崩溃掉。  这个崩溃和你说的系统知道了指针所指的长度没有关系。

user: user-0
content: 引用 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));的什么区别导致了上述结果呢？

user: user-0
content: 引用 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]  太谢谢了。

user: user-2
content: 你要弄清楚指针变量的概念，指针变量存储区域的是一个地址 这个地址是指针所指向内存区域的首地址，而指针所指的数据类型是决定所以想的那块地址的长度。

user: user-1
content: 引用 12 楼 u012526168 的回复:[quote=引用 8 楼 zxcvbnm0014 的回复:] /*(p+20) = 'z';  字符数组越界了。p指针指向的数据是char型的，p+1就向后移动一个char所占内存的大小。 谢谢回答，但是我问的不是为什么报错，我是想问机器是怎么知道指针所指的对象的长度的[/quote]  你是怎么知道机器知道了指针所指对象的长度？机器完全不知道它所指向对象的长度，只知道指针类型，而这个类型是你声明了的，就这么简单。没有问题了吧？你不信，你随便给指针赋个值完后再访问看看，你的程序肯定死掉，因为程序根本就没有你想像的那样知道它指向了什么，指向的东西有多长。

user: user-0
content: 引用 10 楼 baichi4141 的回复:建议楼主不要空想 稍微学一下汇编语言，看看你写的代码被编译成了哪些机器命令，就知道空想是多么的无价值了  指针指向内存中的一个位置，这个位置存在或不存在，都和指针没关系 如果你申请了一块内存，那么内存管理机制就会记录下分给你的这块内存的大小及位置。如果指针指向的不是你申请的内存，那么这块内存有谁何时怎么样处理，你都不应该猜想。 char a[] = "hello world!";这条语句定义了一个局部数组，而数组在编译后运行时根本不记录其大小，越界修改将导致修改其他数据从而程序运行出错甚至崩溃，这一切都是程序员自作自受，没有任何安全机制供程序员撒娇。 唉，都不好意思说我已经学过汇编了，当时没好好学。 我提这个问题是这样想的：像i386的段描述符八个字节一部分是用于标记段基址的，一部分是标记段限长的，那为什么指针的四个字节全部标记的是所指对象的地址，没有标记所指对象的长度，那机器是如何知道其长度的，是不是内存管理机制有片空间专门用于记录指针长度的？ 刚才又做了几个实验，字符指针申请了一个字节的内存空间，但是可以在*(P+7)处给予赋值，确实如你所说。 哈哈我都忘了可以反汇编来看执行过程。 谢谢了。

user: user-0
content: 引用 8 楼 zxcvbnm0014 的回复:/*(p+20) = 'z';  字符数组越界了。p指针指向的数据是char型的，p+1就向后移动一个char所占内存的大小。 谢谢回答，但是我问的不是为什么报错，我是想问机器是怎么知道指针所指的对象的长度的

user: user-3
content: 哪怕是同样的申请内存，在不同的内存管理机制中也有不同的实现。 例如MFC的DLL，就是每个DLL分别维持一个内存堆记录，如果你跨DLL进行申请/释放内存，也就是在一个DLL里new另一个DLL里delete，就可能导致该块内存无法被正确释放等后果。 所以不要空想，去学，去查，去理解。没有知识的想象只能成为妄想，任何踏踏实实学东西的人都不该像民科一样。

user: user-3
content: 建议楼主不要空想 稍微学一下汇编语言，看看你写的代码被编译成了哪些机器命令，就知道空想是多么的无价值了  指针指向内存中的一个位置，这个位置存在或不存在，都和指针没关系 如果你申请了一块内存，那么内存管理机制就会记录下分给你的这块内存的大小及位置。如果指针指向的不是你申请的内存，那么这块内存有谁何时怎么样处理，你都不应该猜想。 char a[] = "hello world!";这条语句定义了一个局部数组，而数组在编译后运行时根本不记录其大小，越界修改将导致修改其他数据从而程序运行出错甚至崩溃，这一切都是程序员自作自受，没有任何安全机制供程序员撒娇。

user: user-0
content: 引用 4 楼 derekrose 的回复:如果是new一个对象  那么内存的大小就是对象的大小  如果new一个数组 那么申请内存的大小就是数组元素的大小乘以数组元素的个数 我想问的是申请的内存大小数值保存在哪？仅有的四个字节32位全部用于记录所指对象的地址了，但是没有记录所指对象占的内存空间大小，那机器如何知道所指的对象的长度呢？应该是一楼说的那样吧。

user: user-2
content: /*(p+20) = 'z';  字符数组越界了。p指针指向的数据是char型的，p+1就向后移动一个char所占内存的大小。

user: user-0
content: 引用 2 楼 xia597289162 的回复:p保存的是数组a的地址， 当p++的地址超过a 分配的地址，后面的数据是随机值的。p只是以a地址为起始地址。 真不好意思，回复错了，想回复三楼的，回复给你了

user: user-0
content: 引用 2 楼 xia597289162 的回复:p保存的是数组a的地址， 当p++的地址超过a 分配的地址，后面的数据是随机值的。p只是以a地址为起始地址。 又试了几个越界的数，不行，将20换成13,14,15...都不行，指针使用前还是要声明内存空间大小的，看来这里就是将a的长度传给了p，越界就可能有问题。

user: user-0
content: 引用 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'注释了就能了

user: user-4
content: 如果是new一个对象  那么内存的大小就是对象的大小  如果new一个数组 那么申请内存的大小就是数组元素的大小乘以数组元素的个数

user: user-5
content: 用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'作判断

user: user-6
content: p保存的是数组a的地址， 当p++的地址超过a 分配的地址，后面的数据是随机值的。p只是以a地址为起始地址。

user: user-7
content: 申请内存的时候，内存库会记录下来某个指针对应的内存块大小的