在C语言中交换两个数组

6

我需要在一个函数中交换两个数组的值。问题是我不能改变主函数,只能改变这个函数本身。它应该接收两个整数数组,并交换它们的值。问题是,我不知道这些数组的大小,根据我的理解它们甚至可以是不同的大小。尝试使用以下代码:

    int main()
{
    int size = 4;  //Please notice that I'm using this only to print the array
    int a[] = {1,2,3,4};
    int b[] = {5,6,7,8};
    printArr(a,"a",size);
    printArr(b,"b",size);
    swapArray(a,b);
    printf("Swapped:\n");
    printArr(a,"a",size);
    printArr(b,"b",size);
}

并且这个函数:
 void swapArray(int **a,int **b)
{
    int *p = *a;
    *a = *b;
    *b = p;
}

而printArr只是简单地打印数组:

void printArr(int arr[],char name[],int size)
{
    printf("%s:\t",name);
    for(int i=0;i<size;i++){
        printf("%d\t",arr[i]);
    }
    printf("\n");
}

我得到了一个非常奇怪的结果:
a:   1    2    3   4
b:   5    6    7   8
Swapped:
a:   5    6    3   4
b:   1    2    7   8

我希望能够了解为什么会发生这种情况,而不仅仅是一个可行的解决方案。 谢谢您 :)


5
如果你启用编译警告,编译器会给出一些非常有帮助的信息,说明你做错了什么,特别是关于你对swapArray的调用(即使我很惊讶它能通过编译)。 - Paul R
1
你确定你正确地阅读了任务吗?像那样交换硬编码数组甚至没有意义,但交换指针(可能作为数组的指针)是可以的。 - John Coleman
4个回答

6
在这个调用中
swapArray(a,b);

参数表达式的类型为int *,而函数参数的类型为int **。从int *int **没有隐式转换,因此编译器将发出诊断消息。

无论如何,当前实现的swap函数都没有意义。至少您的程序存在未定义行为,因为它试图交换指针而不是数组本身。

请注意,数组虽然不是指针,但在表达式中它们通常会被隐式转换为指向其第一个元素的指针,除非有罕见的例外。

要交换两个数组的元素,必须分别交换每对元素。并且您必须提供数组中的元素数量。否则,数组需要具有哨兵值。

下面是一个演示程序,展示了如何定义swap函数。

#include <stdio.h>

void printArr( const int a[], size_t n, const char *s )
{
    printf( "%s:\t", s );

    for ( size_t i = 0; i < n; i++ )
    {
        printf( "%d ", a[i] );
    }
    putchar( '\n' );
}

void swapArray( int *a, int *b, size_t n )
{
    for ( size_t i = 0; i < n; i++ )
    {
        int tmp = a[i];
        a[i] = b[i];
        b[i] = tmp;
    }
}

int main(void) 
{
    enum { N = 4 };
    int a[N] = { 1, 2, 3, 4 };
    int b[N] = { 5, 6, 7, 8 };

    printArr( a, N, "a" );
    printArr( b, N, "b" );
    putchar( '\n' );

    swapArray( a, b, N );


    printArr( a, N, "a" );
    printArr( b, N, "b" );
    putchar( '\n' );

    return 0;
}

它的输出结果是

a:  1 2 3 4 
b:  5 6 7 8 

a:  5 6 7 8 
b:  1 2 3 4 

您可以使用指针交换原始数组的可视化表示。但在这种情况下,数组本身不会被交换。
考虑以下程序。
#include <stdio.h>

void printArr( const int a[], size_t n, const char *s )
{
    printf( "%s:\t", s );

    for ( size_t i = 0; i < n; i++ )
    {
        printf( "%d ", a[i] );
    }
    putchar( '\n' );
}

void swapArray( int **a, int **b )
{
    int *tmp = *a;
    *a = *b;
    *b = tmp;
}

int main(void) 
{
    enum { N = 4 };
    int a[N] = { 1, 2, 3, 4 };
    int b[N] = { 5, 6, 7, 8 };

    printArr( a, N, "a" );
    printArr( b, N, "b" );
    putchar( '\n' );

    int *pa = a;
    int *pb = b;

    swapArray( &pa, &pb );

    printArr( pa, N, "pa" );
    printArr( pb, N, "pb" );
    putchar( '\n' );

    printArr( a, N, "a" );
    printArr( b, N, "b" );
    putchar( '\n' );

    return 0;
}

它的输出结果是

a:  1 2 3 4 
b:  5 6 7 8 

pa: 5 6 7 8 
pb: 1 2 3 4 

a:  1 2 3 4 
b:  5 6 7 8 

正如您所看到的,数组并没有交换。但是指向数组第一个元素的指针已经交换了。使用这些指针,您可以模拟交换数组。

C++与C相反,有一个模板函数std::swap用于数组,可以像这样简单地调用

std::swap( a, b );

4
在C语言中,数组不是可以直接交换的单个"物件"。你需要逐个元素地进行交换。 唯一一种可以在一次操作中交换这些数组"物件"的情况是它们指向数组的指针。
int *a = malloc(n*sizeof(int));
int *b = malloc(n*sizeof(int));
int *tmp;
tmp=a; a=b; b=tmp;

非常感谢。不幸的是,我无法使用malloc。作业从一开始就有误,但至少在这个过程中我学到了很多。 - Dr.Java

4
我猜您的平台上指针大小为64位,而int大小为32位。调用swapArray时,编译器会隐式地将您的int数组重新解释为指针数组。 (这些是指向int的指针,但在此无关紧要)。 swapArray然后只交换这些指针数组的第一个元素。幸运的是,您原始的int数组足够大,因此不会发生非法访问。由于指针是64位,因此对应于被交换的两个int

这解释了很多!非常感谢。 - Dr.Java

1
问题是,我不知道数组的大小,据我所知它们甚至可以是不同的大小。
那么让我们使用不同的大小!但我不想支持“复制和粘贴行为”,因此我不会提供完整的程序。我只提供一些快捷方式并解释它们。
正如其他答案中已经展示的那样,如果你将一个数组 x[] 传递给像 swapArray() 这样的函数,你需要指定它的大小。
但在你的 main() 函数中,你正在静态地定义你的两个数组。让我这样做:
int a[] = { 1, 2, 3 };
int b[] = { 5, 6, 7, 8, 9 };

这里我们定义了两个静态数组,它们的大小不同。但是大小是已知的,编译器在构建/编译时就知道了它们的大小。有一个构建时间运算符sizeof(),它在编译时返回类型或变量的大小。因此,我们可以使用sizeof(a)来获取数组a的大小。
但是有一个小问题: sizeof()返回的“单位”是字节而不是元素。因此,我们必须将其除以类型的大小(这里是int)才能获得数组中实际的元素数量:
size_t size_a = sizeof(a) / sizeof(int);
< p > (实际上,这意味着例如size_a将以12/4结束,这实际上会在您编译的程序中作为预计算值写入3。我假设这里int占用4个字节。)

对于交换函数,您必须传递size_asize_b的< strong >较低< / strong >值。我们可以使用以下方法简单地获取最小值:

size_t size_min = (size_a < size_b) ? size_a : size_b;

如果size_asize_b小,则选择size_a。否则选择size_b。此计算在运行时进行。(如果您希望在构建时执行此操作,因为有静态值,则需要使用预处理指令。)
调用printArr()很简单,只需传递正确的大小:
printArr(b,"b",size_b);

对于交换使用 size_min

swapArray(a, b, size_min);

处理不同大小的数组就是这些。一个非常简单的swapArray()可能如下所示:
void swapArray(int a[],int b[], size_t size) { // or int *a, int *b...
  while (size > 0) {
    size--;
    int tmp = a[size];
    a[size] = b[size];
    b[size] = tmp;
  }
}

我们不需要定义一个额外的循环变量,因为我们可以简单地使用 size 并将其减少到达0。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接