【问题标题】:Program doesn't output anything using a dynamic array程序不使用动态数组输出任何内容
【发布时间】:2020-01-14 21:25:36
【问题描述】:

我刚开始使用 C,我正在尝试创建一个程序,该程序接受一个数字并使用这种方法将其转换为二进制(来自 indepth.dev):

要将整数转换为二进制,请从所讨论的整数开始,然后将其除以 2,同时注意商和余数。继续将商除以 2,直到商为零。然后以相反的顺序写出余数。 (...) 现在,我们只需要以相反的顺序写出余数——1100。所以,十进制的 12 表示为二进制的 1100。

我正在尝试使数组的大小动态化。来自 Python 这有点令人困惑,因为在 Python 中你可以只追加到一个列表。

到目前为止,这是我的代码:

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

int main() 
{
    int *ptr, n, i;
    ptr = (int*)malloc(1 * sizeof(int));
    printf("Enter a number to convert: ");
    scanf("%d", &n);
    for (i = 0; n>0; i++)
    {   
        ptr = realloc(ptr, i * sizeof(int));
        ptr[i] = n % 2;
        n = n/2;

    }

    for(i=i-1; i>= 0; i--)
    {
        printf("%d", ptr[i]);
    }
    free(ptr);
    return 0;
}

当我运行程序并输入一个数字时,它不会输出任何内容。如果我对固定的数组大小做同样的事情,它就可以工作。为什么会这样?

【问题讨论】:

  • 在第一个循环步骤中,realloc 的大小是多少?接下来呢?
  • 在 for 循环中 ptr 的大小始终为 i,但是,您正在写入 ptr[i] 超出范围。此外,第一次通过第二个循环时,您读取的 ptr[i] 也超出了范围。
  • 这里不需要动态分配。您的输入是一个 int,因此只需将您的数组声明为具有与 int 中的位一样多的元素(可能是 32,也可能是 64)。
  • 你已经包含了数学(似乎没有合理的理由),为什么不利用log10() 来计算所需的数组元素的数量并只分配一次呢?

标签: c arrays malloc


【解决方案1】:

问题在于这几行:

for (i = 0; n>0; i++)
{   
    ptr = realloc(ptr, i * sizeof(int));
    ptr[i] = n % 2;
    n = n/2;
}

您正在重新分配一个能够每次保存i 整数的数组,但是您最终会写入索引i。包含i 整数的数组的索引从0i - 1,因此您正在写入数组末尾。这会导致未定义的行为

最简单的解决方法是从i = 1 开始,然后写信给ptr[i - 1]

for (i = 1; n > 0; i++)
{   
    ptr = realloc(ptr, i * sizeof(int));
    ptr[i - 1] = n % 2;
    n = n/2;
}

更简单的方法是使用固定大小的数组。您已经知道 int 的长度为 8*sizeof(int) 位,所以这是您需要的最大值。此外,您可能不需要使用有符号整数,因为它们可能会导致负值问题(因此您可以使用unsigned)。

编辑:我说的是8 * sizeof(int),因为sizeof 运算符以字节为单位返回类型的大小(在本例中为int)。一个字节是 8 位,所以我将它乘以 8 以获得以位为单位的大小。我在这里说8,但使用CHAR_BIT(来自limits.h)会更好,因为C 中的“字节”可以使用超过8 位来表示,在这种情况下CHAR_BIT 拥有正确的位数每个字节。我不知道有任何 C 实现的值不同于 8CHAR_BIT,但它仍然是正确的方法。我更新了下面的代码以使用CHAR_BIT 而不是8

#include <stdio.h>
#include <limits.h>
#define N_BITS CHAR_BIT * sizeof(unsigned)

int main(void) {
    unsigned digits[N_BITS] = {0}; // Start with an array filled with zeroes.
    unsigned n;
    int i;

    printf("Enter a number to convert: ");
    scanf("%u", &n);

    // Calculate binary digits.
    for (i = 0; n > 0; i++) {
        digits[i] = n % 2;
        n /= 2;
    }

    // Skip leading zeroes.
    while (digits[i] == 0)
        i--;

    // Print binary digits in reverse order.
    for(; i >= 0; i--)
        printf("%u", digits[i]);

    // Final newline.
    putchar('\n');

    return 0;
}

奖金:

#include <stdio.h>

int main(void) {
    int i = 8 * sizeof(unsigned);
    unsigned n;

    printf("Enter a number to convert: ");
    scanf("%u", &n);

    while (i--)
        putchar('0' + ((n >> i) & 1));
    putchar('\n');

    return 0;
}

【讨论】:

  • 感谢您的回答。您能解释一下为什么将 N_BITS 定义为 8 * sizeof(unsigned) 吗?输入的最大尺寸是多少?
  • @Shadow 我已经编辑了我的答案,并为此添加了解释。
【解决方案2】:

您分配的内存不足。如果sizeof( int )等于4,那么二进制位数可以等于32sizeof( int ) * CHAR_BIT)。

而且没有必要使用realloc。

还有这个说法

ptr = realloc(ptr, i * sizeof(int));

当循环中的i 等于 0 时分配大小为零的内存。您不能写入这样的内存。

您还应该使用 unsigned int 类型的对象。

这是一个演示程序。

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

int main(void) 
{
    unsigned int Base = 2;

    int *ptr = malloc( CHAR_BIT * sizeof( unsigned int ) );

    printf( "Enter a number to convert: " );

    unsigned int x = 0;

    scanf( "%u", &x );

    size_t n = 0;

    do
    {
        ptr[n++] = x % Base; 
    } while ( x /= Base );

    while ( n-- )
    {
        printf( "%u", ptr[n] );
    }
    putchar( '\n' );

    free( ptr );

    return 0;
}

它的输出可能看起来像

Enter a number to convert: 12
1100

如果你想使用realloc 那么代码可以是这样的

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

int main(void) 
{
    unsigned int Base = 2;

    int *ptr = NULL;

    printf( "Enter a number to convert: " );

    unsigned int x = 0;

    scanf( "%u", &x );

    size_t n = 0;

    do
    {
        ptr = realloc( ptr, ( n + 1 ) * sizeof( unsigned int ) );
        ptr[n++] = x % Base; 
    } while ( x /= Base );

    while ( n-- )
    {
        printf( "%u", ptr[n] );
    }
    putchar( '\n' );

    free( ptr );

    return 0;
}

一般是这样的调用

ptr = realloc( ptr, ( n + 1 ) * sizeof( unsigned int ) );

是不安全的,因为该函数可以返回 NULL。所以一般来说你应该使用一个中间变量,比如

unsigned int *tmp = realloc( ptr, ( n + 1 ) * sizeof( unsigned int ) );
if ( tmp ) ptr = tmp;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-08
    • 1970-01-01
    • 1970-01-01
    • 2012-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多