【问题标题】:Getting address boundary error when working with pointers in C在 C 中使用指针时出现地址边界错误
【发布时间】:2021-06-10 20:36:50
【问题描述】:

下面的代码给了我一个terminated by signal SIGSEGV (Address boundary error)

void rec(int x, int *arr, int *size) {
  if (x < 0) {
      rec(-x, arr, size);
      return;
  }
  arr = realloc(arr, sizeof(int) * ++(*size));
  *(arr + (*size) - 1) = x % 10;
  if (x % 10 != x)
      rec(x / 10, arr, size);
}

int main() {
    int *arr = malloc(sizeof(int));
    int *size = malloc(sizeof(int));
    *size = 0;
    rec(20, arr, 0);
}

我已经发现 main 方法中的 arr 计数器无法保持所需的结果,但我仍然不明白为什么会出现错误。

【问题讨论】:

  • 你知道Hilberto1吗?此代码与stackoverflow.com/questions/66603006/… 非常相似
  • 我认为这是重新发布一个封闭的问题
  • @Barmar 你的回答很遗憾没有解决我的问题
  • 因为你有多个错误,而我没有注意到第二个。
  • 你是同一张海报吗?如果副本没有解决问题,您应该要求重新打开它。

标签: c dynamic-memory-allocation realloc function-definition null-pointer


【解决方案1】:

请注意,您将 NULL 作为第三个参数传递:

rec(20, arr, 0); // 0 is NULL

你会得到一个取消引用它的段错误:

arr = realloc(arr, sizeof(int) * ++(*size)); // here size is `NULL`

试试

rec(20, arr, size);

【讨论】:

  • sry 我很迷茫,我没有注意到我在那里放了一个 0。天哪,多么愚蠢的错误
  • 不要自责,@Descrates!曾经我一直在努力弄清楚为什么我的数据处理会给我带来疯狂的结果,直到我想起字节有 8 位而不是 4 位。
  • 顺便说一句,没有必要动态分配size。只需声明int size = 0; 并传递&amp;size
【解决方案2】:

对于初学者来说,这些内存分配

int *arr = malloc(sizeof(int));
int *size = malloc(sizeof(int));

没有意义。它们是多余的。

你可以写

int *arr = NULL;
size_t size = 0;

其次,变量 size 已声明但未使用,因为您传递的不是变量,而是整数常量 0

rec(20, arr, 0);

所以在函数rec

void rec(int x, int *arr, int *size);

指针size由空指针常量0初始化。即size是函数内的空指针,使用空指针访问内存会导致未定义的行为。

您还应该通过引用将指针传递给函数。否则将它传递给函数没有多大意义,因为 main 中的指针不会改变。

main 中的代码可能如下所示

int *arr = NULL;
size_t size = 0;

rec( 20, &arr, &size );

注意,当分配的内存不再使用时,应该释放所有分配的内存。

相应地,函数应该声明为

void rec(int x, int **arr, size_t *size);

使用size_t 类型而不是int 类型,因为这个无符号整数类型是函数realloc 的第二个参数的类型。

一般来说,要得到 realloc 的结果,你应该使用一个中间变量,因为函数可以返回一个空指针,当前指针会丢失。

还要注意函数的调用是不安全的,会因为这个if语句导致无限递归

  if (x < 0) {
      rec(-x, arr, size);
      return;
  }

当用户将 x 的值传递给函数时,等于 INT_MIN

考虑以下演示程序。

#include <stdio.h>
#include <limits.h>

int main(void) 
{
    int x = INT_MIN;
    
    printf( "x = %d\n", x );
    printf( "-x = %d\n", -x );

    return 0;
}

它的输出可能看起来像

x = -2147483648
-x = -2147483648

如您所见,否定变量 x 的值会得到相同的负值。所以也许最好将第一个函数参数声明为具有unsigned int 类型。

您的函数可以如下面的演示程序所示。

#include <stdio.h>
#include <stdlib.h>

int rec( unsigned int x, unsigned int **arr, size_t *size ) 
{
    const unsigned int Base = 10;
    
    unsigned int *tmp = realloc( *arr, sizeof( int ) * ++*size );
    int success = tmp != NULL;
    
    if ( success )
    {
        *arr = tmp; 
        *( *arr + *size - 1 ) = x % Base;
        if ( x % Base != x )
        {
            success = rec( x / Base, arr, size );
        }
    }
    
    return success;
}

int main(void) 
{
    unsigned int *arr = NULL;
    size_t size = 0;
    
    rec( 123456789, &arr, &size );
    
    for ( size_t i = 0; i < size; i++ )
    {
        printf( "%u", *( arr + i ) );
    }
    
    putchar( '\n');
    
    free( arr );
    
    return 0;
}

程序输出是

987654321

【讨论】:

  • int *arr = NULL 是否在堆上分配内存?
  • @Descrates 不,它没有。您需要在 main 中分配内存,因为该内存未使用,并且会立即在函数内重新分配。
  • 最后一个问题:arr[i][j] 表示法是否比 *(*(arr + j) + i) 更受欢迎,因为它具有更好的可读性?
  • @Descrates Yes 使用下标运算符使代码更具可读性。
  • @VladfromMoscow 在每次递归中调用 realloc 只是为了将大小增加 4 个字节真的可行吗? (假设 sizeof(int) == 4)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-19
  • 2021-08-29
  • 2019-09-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多