为什么这样做?C中的字符指针
Why does this work? Character pointer in C
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
int main()
{
char* s = (char*)malloc(sizeof(char) * 3); //I allocate memory for 3 chars
s[0] = 'a';
s[1] = 'b';
s[2] = ' ';
s[3] = 'd'; //This shouldn't work
std::cout << s[3] << std::endl; //It prints out d, why?
free(s);
return 0;
}
为什么允许我写信给s[3]?
这被称为未定义行为。
编译器不会阻止你做非法的事情;但是,编译后的代码可能不会达到您所期望的效果。
通常,函数malloc会分配一些最小数量的字节,例如16,即使您将请求只分配一个(或如示例中的3个)字节。
但是,您不应依赖该功能的此类功能。它是由实现定义的malloc如何分配内存。因此,您的代码具有未定义的行为。
进程甚至可以允许在s[100]上进行写入,但在大多数情况下,它会破坏进程地址空间,并产生难以调试的问题。有时,如果写入的地址不在进程地址空间中,则写入到这样的位置会导致分段错误,但我们不会总是遇到访问冲突,因为地址可能非常在进程的地址空间中。
基本上,在C/C++中,这些都是人们应该非常小心的问题。因为记忆力的衰退会在其他一些地方表现出来,导致奇怪的行为,我们需要花几个小时在大海捞针。像electric fence、Valgrind、cppcheck这样的工具有助于隔离此类错误,但即使是它们也可能无法检测到内存损坏的原因。特别是电动围栏只适用于小程序,cppcheck只能进行静态检查,valgrind会大大减慢过程。
您在不属于自己的内存中进行写入。您可以这样做,但这会侵犯您的地址空间,可能会导致分段错误。
在这种情况下,它正在工作并打印d
,但不能保证在其他机器中发生,甚至不能保证在您自己机器中其他编译器编译的代码中发生。这被称为未定义行为。
为什么允许我写入s[3]?
因为你没有被禁止这样做。
这将导致未定义的行为,因为您试图触摸未分配给您的内存。
s[3] = 'd';
它可以调用未定义的行为。它不会阻止您写入相邻的内存位置,但在您访问它时会有不同的行为,因为它不是由您分配的。
您正在写入未分配的内存位置。如果此位置属于另一个程序,则您的程序可能会出现错误。如果它属于操作系统保留内存,则可能会出现分段错误或程序崩溃。这是未定义的行为。
啊,这种问题每周都会出现…
在每个C教程中必须说明的一件事是:C库的环境和运行时不能保证任何误用、类型错误的访问或其他定义不好的操作都会被捕获并正确报告。这一点的要点是效率。您遵守规则(并负责实现这些规则),运行时是围绕这些规则构建的,可以有效地将编程环境模型代理到硬件和内核。
请注意发生这种情况的原因。您在C中看到的环境及其运行库比实际执行此任务的底层机制简单得多。在这种情况下,您可以看到malloc
从系统中获得了一大块内存到进程的动态数据部分,并返回了较小子块的地址,并记住它在自己的结构中使用。代码试图执行的操作称为缓冲区溢出。它真正做的是:破坏malloc的内部结构,或者写入另一个分配的块(导致严重的延迟问题),或者写入未分配的部分(导致当前进程的未来绝对没有问题)。
- 将字符指针十六进制转换为字符串并保存在文本文件C++中
- 如何循环访问 cpp 中的函数返回的字符指针数组
- 将(N 个字节)无符号字符指针转换为浮点数和双 C++
- 字符指针的 Qt 数组
- C++将常量字符* 指针数组传递给对象
- 为什么不能将字符指针定义为数组?
- 在函数内初始化无符号字符指针将返回空指针
- 将字符指针存储到容器中
- 为什么 strtok_r() 只接受字符数组而不接受字符指针
- 字符指针数组内存分配
- 字符指针不递增?
- 如何在C++中使用字符指针
- 确保字符指针始终指向相同的字符串文字
- C++中的字符指针
- 使用unique_ptr的常量字符指针
- 字符指针不断意外更改
- 将字符指针中的十六进制转换为十进制
- 如何将字符*(字符指针)转换为 PCSZ?
- 在向量中存储字符指针
- 字符指针具有不同的值