【问题标题】:Junk when printing C array打印 C 数组时出现垃圾
【发布时间】:2022-01-03 16:50:06
【问题描述】:

我用 C 编程语言实现了一个程序来反转整数数组(作为练习)

#include <stdio.h>

#define procedure void

procedure reverse_arr(int A[], size_t N)
{
    for(int i = 0; i < N / 2; i++){
        A[i] = A[i] ^ A[N-1-i];
        A[N-1-i] = A[N-1-i] ^ A[i]; 
        A[i] = A[i] ^ A[N-1-i];
    }
}

procedure print_array(int A[], size_t N)
{
    for(int i = 0; i < N; i++)
        printf("%d\n", A[i]);
}

int main()
{
    int A[5] = {1, 2, 3, 4 ,5};
    print_array(A, sizeof(A));
    reverse_arr(A, sizeof(A));
    print_array(A, sizeof(A));
}

我已经对其进行了测试,它给了我以下结果:

1 2 3 4 5 0 -13168 0 -13088 0 -2147180803 1 -2139062144 -2139062144 -2147180911 1 -13168 0 6 0 0 6 0 -13168 1 -2147180911 -2139062144 -2139062144 1 -2147180803 0 -13088 0 -13168 0 5 4 3 2 1

如您所见,一开始它打印原始数组,最后打印反向数组,但为什么它打印中间的垃圾?数组大小似乎没有问题,据我所知,在将其作为函数参数传递时,在编译时不需要知道一维数组的大小。

我正在使用 minGW GCC 在 windows x64 上编译。

【问题讨论】:

  • sizeof(A) / sizeof(int)
  • 感谢 Hans Passant,这是打印垃圾的原因,我重新编译了程序,现在可以正常工作了。回答 Lundins 的问题,使用 xor 算法是我们评估策展人的一个条件。
  • #define void 是最愚蠢的事情。您正在更改关键字的含义。
  • #define procedure void C 不是帕斯卡。不要让它看起来像帕斯卡。

标签: arrays c for-loop sizeof function-definition


【解决方案1】:
  1. 我不会做 xor magix
  2. sizeof(A)字节而不是元素为单位给出数组的大小。
  3. 请勿将 C 关键字替换为不需要的 #defines
#include <stdio.h>

void reverse_arr(int *A, size_t N)
{
    int *end;
    if(A && N)
    {
        end = A + N - 1;
        while(end > A)
        {
            int tmp = *A;
            *A++ = *end;
            *end-- = tmp;
        }
    }
}

void print_array(int A[], size_t N)
{
    for(int i = 0; i < N; i++)
        printf("%d\n", A[i]);
}

int main()
{
    int A[5] = {1, 2, 3, 4 ,5};
    print_array(A, sizeof(A) / sizeof(*A));
    reverse_arr(A, sizeof(A) / sizeof(*A));
    print_array(A, sizeof(A) / sizeof(*A));
}

【讨论】:

    【解决方案2】:

    表达式sizeof(A) 产生整个数组的大小,计算方式类似于5 * sizeof( int ),如果sizeof( int ) 等于4,那么表达式sizeof( A ) 返回的值将等于@987654326 @。

    要确定数组中元素的数量,您需要使用表达式

    sizeof( A ) / sizeof( *A )
    

    虽然为数组中的元素数量定义一个命名常量会更简单,例如

    int A[] = {1, 2, 3, 4 ,5};
    const size_t N = sizeof( A ) / sizeof( *A );
    
    print_array( A, N);
    reverse_arr( A, N);
    print_array( A, N );
    

    请注意,使用大写字母命名标识符是个坏主意。通常大写字母用于命名宏或常量。

    还引入了像这样的宏别名

    #define procedure void
    

    只会让代码的读者感到困惑。

    由于函数print_array 不会更改传递的数组,因此它的第一个参数应该有限定符const

    此外,函数的第二个参数的类型为 size_t,而在 for 循环中的函数内,您使用的是 int 类型的索引。

    函数应该通过以下方式声明和定义

    void print_array( const int a[], size_t n )
    {
        for ( size_t i = 0; i < n; i++ )
            printf("%d ", a[i]);
    }
    

    调用函数后你应该打印换行符

    putchar( '\n' );
    

    否则所有输出将在同一行。

    当引入中间变量时,使用通用方法代替使用运算符 ^ 交换整数要好得多。这使代码更具可读性。让代码读者的生活更轻松。:)

    函数reverse_arr可以通过以下方式声明和定义

    void reverse_arr( int a[], size_t n )
    {
        for ( size_t i = 0; i < n / 2; i++ )
        {
            int tmp = a[i];
            a[i] = a[n - i - 1];
            a[n - i - 1] = tmp;  
        }
    }
    

    因此您的程序可以如下所示

    #include <stdio.h>
    
    void reverse_arr( int a[], size_t n )
    {
        for ( size_t i = 0; i < n / 2; i++ )
        {
            int tmp = a[i];
            a[i] = a[n - i - 1];
            a[n - i - 1] = tmp;  
        }
    }
    
    void print_array( const int a[], size_t n )
    {
        for ( size_t i = 0; i < n; i++ )
            printf( "%d ", a[i] );
    }
    
    int main( void )
    {
        int a[] = { 1, 2, 3, 4 ,5 };
        const size_t N = sizeof( a ) / sizeof( *a );
    
        print_array( a, N );
        putchar( '\n' );
    
        reverse_arr( a, N );
    
        print_array( a, N );
        putchar( '\n' );
    }
    

    程序输出是

    1 2 3 4 5 
    5 4 3 2 1 
    

    【讨论】: