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

时间:2014-02-16 13:40:46

标签: c++ c pointers memory-management undefined-behavior

#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] = '\0';
    s[3] = 'd'; //This shouldn't work

    std::cout << s[3] << std::endl; //It prints out d, why?

    free(s);        
    return 0;
}

为什么我可以写s [3]?

8 个答案:

答案 0 :(得分:6)

这称为未定义的行为

编译器不会阻止你做违法的事情;但是,编译后的代码可能无法达到预期效果。

答案 1 :(得分:5)

通常函数malloc为示例16分配一些最小字节数,即使您将请求仅分配一个(或在示例中为3个)字节。

但是你不应该依赖这个功能的这个功能。实现定义了malloc如何分配内存。所以你的代码有不确定的行为。

答案 2 :(得分:2)

该过程甚至可以允许在s [100]上写入,但在大多数情况下它会破坏进程地址空间并导致难以调试的问题。如果写入的地址不属于进程地址空间,有时写入这样的位置会导致分段错误,但是我们不会总是得到访问冲突,因为地址可能非常落在进程的地址空间中。

基本上,在C / C ++中,这些是人们应该非常小心的一些问题。因为记忆的腐败在其他一些地方表现出来,导致奇怪的行为,我们需要花费数小时在大海捞针寻找针头。像电围栏,Valgrind,cppcheck这样的工具有助于隔离这些错误,但即使它们可能无法检测到内存损坏的原因。特别是电围栏只适用于小型程序,cppcheck只能进行静态检查,而valgrind会大大减慢这个过程。

答案 3 :(得分:1)

你写的是你不拥有的记忆。您可以这样做,但它违反了您的地址空间,可能会导致分段错误。

在这种情况下,它正在工作并打印d,但不能保证在其他计算机中或甚至在您自己的计算机中由其他编译器编译的代码中发生。它被称为未定义的行为。

答案 4 :(得分:1)

  

为什么我可以写s [3]?

因为你不禁止这样做。

这会导致未定义的行为,因为您正在尝试触摸未为您分配的内存。

答案 5 :(得分:1)

s[3] = 'd';它可以调用未定义的行为。它不会阻止您写入相邻的内存位置,但在访问它时会有不同的行为,因为它不是由您分配的。

答案 6 :(得分:1)

您正在写入未分配的内存位置。如果此位置属于另一个程序,则您的程序可能会出现错误行为。如果它属于OS保留内存,则可能会出现分段错误或程序崩溃。这是未定义的行为。

答案 7 :(得分:1)

啊,这个问题每周都会出现......

每个C教程都必须说明一件事:C库的环境和运行时不保证任何滥用,输入错误的访问或其他未明确定义的操作都会被捕获并正确报告。其重点是效率。您遵守规则(并负责实现它们),并且运行时是围绕它们构建的,有效地将编程环境模型代理到硬件和内核。

请注意为什么会这样。您在C及其运行时库中看到的环境比实际执行该工作的基础机制简单得多。在这种情况下,您会看到malloc从系统中获得了大量内存到进程的动态数据部分,并返回了较小子块的地址,并记住它正在使用中#39自己的结构。您的代码尝试执行的操作称为缓冲区溢出。它真正做的是:摧毁malloc的内部结构,或写入另一个分配的块(导致严重的延迟问题),或写入未分配的部分(导致当前进程的未来绝对没有问题)。