首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >时间(*p++)危险吗?

时间(*p++)危险吗?
EN

Stack Overflow用户
提问于 2014-10-03 15:18:14
回答 6查看 806关注 0票数 3

是否使用while(*p++)检查数组是否有更多的危险元素?

如果在下一个内存位置上有一些值,并且这个值不是数组的一部分,那么可能会出现问题。

这个简单的代码:

代码语言:javascript
复制
#include <stdio.h>

void f(float *p) {
    printf("%p : %.f\n", p, *p);
    while(*p++){
        printf("%p : %.f\n", p, *p);
    }
    printf("%p : %.f\n", p, *p);
}

int main() {
    float p[] = {2.2, 3.2};
    f(p);
    return 0;
}

给出这个输出:

代码语言:javascript
复制
0x7fffed4e8f10 : 2
0x7fffed4e8f14 : 3
0x7fffed4e8f18 : 0
0x7fffed4e8f1c : 0

因此,如果在0x7fffed4e8f18上值为≠0,它会使我的代码出错吗?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2014-10-03 15:55:20

已经有很多答案能够很好地解释通过数组边界而产生的未定义行为。但还有另一个(潜在的)问题,还没有人提过。

如果数组可以包含0作为有效值,那么您将假定错误的大小。那是,

代码语言:javascript
复制
void
f(float * p)
{
  do
    {
      printf("% .01f\n", *p);
    }
  while(*p++);
}

int
main()
{
  float p[] = {-1.0f, -0.5f, 0.0f, 0.5f, 1.0f};
  f(p);
  return 0;
}

威尔输出

代码语言:javascript
复制
-1.00
-0.50
 0.00

“忽略”剩下的元素。虽然这个特定的示例不会调用未定义的行为,但它可能不是您所期望的。

我想您已经用字符串编程来改变这种模式了。按照约定,我们需要一个字符数组来表示文本字符串。

  1. 不包含任何NUL字节和
  2. 通过在最后一个字节之后放置一个NUL字节来终止。

如果这两项要求都得到满足,请执行

代码语言:javascript
复制
void
roll_all_over_it(char * string)
{
  while(*string);
    {
      putchar(*string++);
    }
}

按合同是安全的。

这使得使用字符串更加方便,因为我们不需要在每个字符串旁边维护一个整数来跟踪它的长度。另一方面,它使相当多的(不小心编写的)程序容易受到缓冲区溢出攻击,而且这个假设还会产生其他问题。例如,请参见fgetsGNU libc手册中的讨论

警告:如果输入数据有空字符,则无法判断。因此,除非您知道数据不能包含null,否则不要使用fgets。不要使用它读取用户编辑的文件,因为如果用户插入空字符,则应该正确处理该字符或打印清楚的错误消息。我们建议使用getline而不是fgets

票数 3
EN

Stack Overflow用户

发布于 2014-10-03 15:21:40

一旦p超出了数组的界限,取消引用它就会调用未定义的行为。所以是的,这样做是危险的。

票数 8
EN

Stack Overflow用户

发布于 2014-10-03 15:26:15

是的,它是:您的函数接受一个指针参数,但是您没有检查以确保它不是空指针。不允许删除空指针。

正如其他人所指出的:取消引用无效指针(超出界限)会导致未定义的bahviour,这是不好的。

此外,您正在使用正确的格式字符串打印指针(%p),但使用-Wall -pedantic编译代码。打印指针值是必须转换到void *的指针的少数几种情况之一。换法:

代码语言:javascript
复制
printf("%p : %.f\n", p, *p);

代码语言:javascript
复制
printf("%p : %.f\n", (void *) p, *p);

最新情况:

作为对您的评论的回应:您似乎实际上试图确定作为参数传递的数组的长度。简单的事实是,你不能。一个数组衰变成一个指针。指针不是数组,因此无法确定原始数组的长度。至少:不可靠。

如果您正在处理一个数组,并且您想知道它的长度:让函数的调用方传递长度作为参数:

代码语言:javascript
复制
void f(float *arr, size_t arr_len)
{
    if (arr == NULL)
        exit( EXIT_FAILURE );//handle error
    //do stuff
}

简而言之,函数在很大程度上依赖于数组后面有一个0。函数本身也可以通过NULL调用,取消引用null也是非法的。所以是的,你的密码很危险。

代码语言:javascript
复制
//example setup
float foo = 123.4f
float *bar = malloc(123 * sizeof *foo);//<-- uninitialized memory, contains junk
//omitting if (bar == NULL) check, so bar might be null
//dangerous calls:
f(&foo);
f(bar);//<-- bar could be null if malloc failed, and contains junk if it didn't dangerous
f(NULL);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26181822

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档