C++ C中的数组索引越界

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/671703/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:38:18  来源:igfitidea点击:

Array index out of bound in C

c++carrays

提问by Kazoom

Why does Cdifferentiates in case of array index out of bound

为什么C在数组索引越界的情况下区分

#include <stdio.h>
int main()
{
    int a[10];
    a[3]=4;
    a[11]=3;//does not give segmentation fault
    a[25]=4;//does not give segmentation fault
    a[20000]=3; //gives segmentation fault
    return 0;
}

I understand that it's trying to access memory allocated to process or thread in case of a[11]or a[25]and it's going out of stack bounds in case of a[20000].

据我所知,它试图在的情况下,分配给进程或线程存取存储器a[11]a[25]与它的情况是怎么回事堆栈出界a[20000]

Why doesn't compiler or linker give an error, aren't they aware of the array size? If not then how does sizeof(a)work correctly?

为什么编译器或链接器不给出错误,他们不知道数组大小吗?如果不是,那么如何sizeof(a)正常工作?

回答by JaredPar

The problem is that C/C++ doesn't actually do any boundary checking with regards to arrays. It depends on the OS to ensure that you are accessing valid memory.

问题是 C/C++ 实际上并没有对数组进行任何边界检查。这取决于操作系统以确保您正在访问有效的内存。

In this particular case, you are declaring a stack based array. Depending upon the particular implementation, accessing outside the bounds of the array will simply access another part of the already allocated stack space (most OS's and threads reserve a certain portion of memory for stack). As long as you just happen to be playing around in the pre-allocated stack space, everything will not crash (note i did not say work).

在这种特殊情况下,您要声明一个基于堆栈的数组。根据特定的实现,在数组边界之外访问将简单地访问已分配堆栈空间的另一部分(大多数操作系统和线程为堆栈保留特定部分的内存)。只要你碰巧在预先分配的堆栈空间中玩耍,一切都不会崩溃(注意我没有说工作)。

What's happening on the last line is that you have now accessed beyond the part of memory that is allocated for the stack. As a result you are indexing into a part of memory that is not allocated to your process or is allocated in a read only fashion. The OS sees this and sends a seg fault to the process.

最后一行发生的事情是您现在访问的内存超出了为堆栈分配的内存部分。因此,您正在索引未分配给您的进程或以只读方式分配的内存部分。操作系统看到这一点并向进程发送段错误。

This is one of the reasons that C/C++ is so dangerous when it comes to boundary checking.

这就是 C/C++ 在边界检查方面如此危险的原因之一。

回答by Johannes Schaub - litb

The segfault is not an intended action of your C program that would tell you that an index is out of bounds. Rather, it is an unintended consequence of undefined behavior.

段错误不是您的 C 程序的预期操作,它会告诉您索引超出范围。相反,它是未定义行为的意外结果。

In C and C++, if you declare an array like

在 C 和 C++ 中,如果你声明一个数组

type name[size];

You are only allowed to access elements with indexes from 0up to size-1. Anything outside of that range causes undefined behavior. If the index was near the range, most probably you read your own program's memory. If the index was largely out of range, most probably your program will be killed by the operating system. But you can't know, anything can happen.

您只能访问索引从0到 的元素size-1。超出该范围的任何事情都会导致未定义的行为。如果索引接近范围,很可能您读取了自己程序的内存。如果索引在很大程度上超出范围,则您的程序很可能会被操作系统杀死。但你不能知道,任何事情都可能发生。

Why does C allow that? Well, the basic gist of C and C++ is to not provide features if they cost performance. C and C++ has been used for ages for highly performance critical systems. C has been used as a implementation language for kernels and programs where access out of array bounds can be useful to get fast access to objects that lie adjacent in memory. Having the compiler forbid this would be for naught.

为什么 C 允许这样做?好吧,C 和 C++ 的基本要点是如果成本性能,则不提供功能。C 和 C++ 已被用于高性能关键系统多年。C 已被用作内核和程序的实现语言,其中数组边界外的访问对于快速访问内存中相邻的对象很有用。让编译器禁止这样做是徒劳的。

Why doesn't it warn about that? Well, you can put warning levels high and hope for the compiler's mercy. This is called quality of implementation(QoI). If some compiler uses open behavior (like, undefined behavior) to do something good, it has a good quality of implementation in that regard.

为什么它不警告呢?好吧,您可以将警告级别设置得很高,并希望编译器能够仁慈。这称为实施质量(QoI)。如果某些编译器使用开放行为(例如未定义的行为)来做一些好事,那么它在这方面的实现质量很好。

[js@HOST2 cpp]$ gcc -Wall -O2 main.c
main.c: In function 'main':
main.c:3: warning: array subscript is above array bounds
[js@HOST2 cpp]$

If it instead would format your hard disk upon seeing the array accessed out of bounds - which would be legal for it - the quality of implementation would be rather bad. I enjoyed to read about that stuff in the ANSI C Rationaledocument.

如果它会在看到数组越界访问时格式化您的硬盘 - 这对它来说是合法的 - 实现的质量会相当糟糕。我很喜欢在ANSI C Rationale文档中阅读有关这些内容的内容。

回答by paxdiablo

You generally only get a segmentation fault if you try to access memory your process doesn't own.

如果您尝试访问您的进程不拥有的内存,通常只会出现分段错误。

What you're seeing in the case of a[11](and a[10]by the way) is memory that your process doesown but doesn't belong to the a[]array. a[25000]is so far from a[], it's probably outside your memory altogether.

什么你在的情况下看到a[11](和a[10]方式)是内存,你的进程确实自己的,但不属于该a[]阵列。a[25000]离 太远了a[],它可能完全超出了您的记忆。

Changing a[11]is far more insidious as it silently affects a different variable (or the stack frame which may cause a different segmentation fault when your function returns).

更改a[11]要隐蔽得多,因为它会默默地影响不同的变量(或在函数返回时可能导致不同分段错误的堆栈帧)。

回答by dmckee --- ex-moderator kitten

C isn't doing this. The OS's virtual memeory subsystem is.

C 没有这样做。操作系统的虚拟内存子系统是。

In the case where you are only slightly out-of-bound you are addressing memeory that isallocated for your program (on the stack call stack in this case). In the case where you are far out-of-bounds you are addressing memory not given over to your program and the OS is throwing a segmentation fault.

在你只略微超出绑定你正解决memeory的情况你的程序(在这种情况下,栈调用堆栈)分配。在您远远超出范围的情况下,您正在寻址未分配给您的程序的内存,并且操作系统会引发分段错误。

On some systems there is also a OS enforced concept of "writeable" memory, and you might be trying to write to memeory that you own but is marked unwriteable.

在某些系统上,还有操作系统强制的“可写”内存概念,您可能正在尝试写入您拥有但被标记为不可写的内存。

回答by BobbyShaftoe

Just to add what other people are saying, you cannot rely on the program simply crashing in these cases, there is no gurantee of what will happen if you attempt to access a memory location beyond the "bounds of the array." It's just the same as if you did something like:

补充一下其他人的说法,在这些情况下,您不能仅仅依赖于程序崩溃,如果您尝试访问超出“数组边界”的内存位置,则无法保证会发生什么。这就像你做了以下事情一样:

int *p;
p = 135;

*p = 14;

That is just random; this might work. It might not. Don't do it. Code to prevent these sorts of problems.

那只是随机的;这可能有效。可能不会。不要这样做。防止此类问题的代码。

回答by Tung Nguyen

As litb mentioned, some compilers can detect some out-of-bounds array accesses at compile time. But bounds checking at compile time won't catch everything:

正如 litb 所提到的,一些编译器可以在编译时检测到一些越界数组访问。但是编译时的边界检查不会捕获所有内容:

int a[10];
int i = some_complicated_function();
printf("%d\n", a[i]);

To detect this, runtime checks would have to be used, and they're avoided in C because of their performance impact. Even with knowledge of a's array size at compile time, i.e. sizeof(a), it can't protect against that without inserting a runtime check.

为了检测到这一点,必须使用运行时检查,并且由于它们的性能影响,它们在 C 中被避免。即使在编译时知道 a 的数组大小,即sizeof(a),它也不能在不插入运行时检查的情况下防止这种情况发生。

回答by Max Lybbert

As I understand the question and comments, you understand why bad things canhappen when you access memory out of bounds, but you're wondering why your particular compiler didn't warn you.

根据我对问题和评论的理解,您明白为什么当您越界访问内存时发生不好的事情,但是您想知道为什么您的特定编译器没有警告您。

Compilers are allowed to warn you, and many do at the highest warning levels. However the standard is written to allow people to run compilers for all sorts of devices, and compilers with all sorts of features so the standard requires the least it can while guaranteeing people can do useful work.

编译器可以向您发出警告,而且很多都在最高警告级别。然而,编写该标准是为了允许人们为各种设备运行编译器,以及具有各种功能的编译器,因此该标准要求最少,同时保证人们可以做有用的工作。

There are a few times the standard requires that a certain coding style will generate a diagnostic. There are several other times where the standard does not require a diagnostic. Even when a diagnostic is required I'm not aware of any place where the standard says what the exact wording should be.

有几次标准要求某种编码风格会产生诊断结果。还有其他几次标准不需要诊断。即使需要进行诊断,我也不知道标准规定了确切措辞的任何地方。

But you're not completely out in the cold here. If your compiler doesn't warn you, Lint may. Additionally, there are a number of tools to detect such problems (at run time) for arrays on the heap, one of the more famous being Electric Fence (or DUMA). But even Electric Fence doesn't guarantee it will catch all overrun errors.

但你在这里并不完全在寒冷中。如果您的编译器没有警告您,Lint 可能会警告您。此外,有许多工具可以检测堆上的数组的此类问题(在运行时),其中最著名的一种是 Electric Fence(或DUMA)。但即使是 Electric Fence 也不能保证它会捕获所有超限错误。

回答by Khadim

C philosophy is always trust the programmer. And also not checking bounds allows the program to run faster.

C 哲学是永远信任程序员。并且不检查边界允许程序运行得更快。

回答by zimbu668

That's not a C issue its an operating system issue. You're program has been granted a certain memory space and anything you do inside of that is fine. The segmentation fault only happens when you access memory outside of your process space.

这不是 C 问题,而是操作系统问题。你的程序被授予了一定的内存空间,你在里面做的任何事情都很好。分段错误仅在您访问进程空间之外的内存时发生。

Not all operating systems have seperate address spaces for each proces, in which case you can corrupt the state of another process or of the operating system with no warning.

并非所有操作系统都为每个进程提供单独的地址空间,在这种情况下,您可能会在没有警告的情况下破坏另一个进程或操作系统的状态。

回答by Jeff

As JaredPar said, C/C++ doesn't always perform range checking. If your program accesses a memory location outside your allocated array, your program may crash, or it may not because it is accessing some other variable on the stack.

正如 JaredPar 所说,C/C++ 并不总是执行范围检查。如果您的程序访问分配的数组之外的内存位置,您的程序可能会崩溃,或者可能不会因为它正在访问堆栈上的某个其他变量。

To answer your question about sizeof operator in C: You can reliably use sizeof(array)/size(array[0]) to determine array size, but using it doesn't mean the compiler will perform any range checking.

在 C 中回答有关 sizeof 运算符的问题:您可以可靠地使用 sizeof(array)/size(array[0]) 来确定数组大小,但使用它并不意味着编译器将执行任何范围检查。

My research showed that C/C++ developers believe that you shouldn't pay for something you don't use, and they trust the programmers to know what they are doing. (see accepted answer to this: Accessing an array out of bounds gives no error, why?)

我的研究表明 C/C++ 开发人员相信你不应该为你不使用的东西付费,他们相信程序员知道他们在做什么。(请参阅对此的公认答案:访问越界数组不会出错,为什么?

If you can use C++ instead of C, maybe use vector? You can use vector[] when you need the performance (but no range checking) or, more preferably, use vector.at() (which has range checking at the cost of performance). Note that vector doesn't automatically increase capacity if it is full: to be safe, use push_back(), which automatically increases capacity if necessary.

如果您可以使用 C++ 而不是 C,也许使用向量?您可以在需要性能时使用 vector[](但没有范围检查),或者更优选地使用 vector.at() (以性能为代价进行范围检查)。请注意,如果 vector 已满,它不会自动增加容量:为了安全起见,请使用 push_back(),它会在必要时自动增加容量。

More information on vector: http://www.cplusplus.com/reference/vector/vector/

有关矢量的更多信息:http: //www.cplusplus.com/reference/vector/vector/