为什么这样做?C中的字符指针

Why does this work? Character pointer in C

本文关键字:字符 指针 这样做 为什么      更新时间:2023-10-16
#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的内部结构,或者写入另一个分配的块(导致严重的延迟问题),或者写入未分配的部分(导致当前进程的未来绝对没有问题)。