0

这可能是一个非常基本的问题,但我对如何实现这样的事情感到困惑。

对于我正在上 CI 的课程,需要采用两个长度不同的数组,并在单独的函数中比较它们的元素。(此函数仅将数组作为参数,而不是它们的大小)两个数组中的任何元素我需要放入另一个数组并返回该数组(注意:每个数组就像一个集合,没有元素在同一个数组中重复)。我已经研究了如何实现这一点,这是我遇到的一些问题。

  1. 我怎么知道数组的末端在哪里?

    我想我看到我可以将 {0} 作为数组中的一个元素来处理空元素。如果这是真的,我不知道我会将这个元素与什么进行比较以检查是否为空。

  2. 我想我应该将指针传递给数组的第一个元素,因为我认为 C 不会让数组的值被传递,但有点不确定。

    如果我确实将数组作为指针传递,我如何访问数组元素以获取它们的数据?

  3. 将数组返回给主函数时,如何在不清理内存的情况下返回结果函数?

    我应该将结果数组设为全局,还是有更好的处理方法?

提前致谢。

4

4 回答 4

2

你的问题有点含糊。看起来您想要实现集合交集,其中您有两个集合,由数组表示,输出是另一个实现为数组的数组。

1.我怎么知道数组的末尾在哪里?

在 C 中,没有办法说出来。如果您不能将长度作为函数传递,那么您将无法做出稳健的解决方案。它需要类似于#2。

2. 我想我看到我可以将 {0} 作为数组中的一个元素来处理空元素。如果这是真的,我不知道我会将这个元素与什么进行比较以检查是否为空。

您可以添加一个空字符,它只是值 0。要检查,您需要与 0 进行比较。我不知道您的每个数组元素由什么组成,但要注意的一件事是没有这些值不再允许为零,因为它被保留为数组标记的结尾。

3. 我认为我应该将指针传递给数组的第一个元素,因为我认为 C 不会让数组的值被传递,但有点不确定。

是的。您将传递指向的第一个元素,它在 C 中是数组符号。

int A[10]; // pass A

4. 如果我确实将数组作为指针传递,我如何访问数组元素以获取它们的数据?

假设您传递了指针 A,您可以通过简单的索引为 A[i] 来访问元素,以获取元素 i。

5. 将数组返回给main函数时,如何在不清理内存的情况下返回结果函数?

在您正在编写的函数中,您可以malloc创建一个数组并将指针传递给 malloc 创建的数组。函数退出时不会删除 Malloce 的内存。

于 2013-02-19T22:35:49.630 回答
1

我怎么知道数组的末端在哪里?

如果您没有将数组的大小作为单独的参数(您应该是)传递,那么您将不得不使用某种标记值(C 字符串在字符串中的最后一个字符之后使用 0 的方式)。

我想我应该将指针传递给数组的第一个元素,因为我认为 C 不会让数组的值被传递,但有点不确定。

C 的数组语义有点棘手。除非它是sizeof, _Alignof, 或一元运算符的操作数&,或者是用于在声明中初始化数组的字符串文字,否则“N-element array of T”类型的表达式将转换为“pointer”类型的表达式到T",表达式的值将是数组中第一个元素的地址。所以,给定代码

int arr1[10];

foo(arr1); // equivalent to foo(&arr1[0]);

arr1调用中的表达式foo将从“10元素数组int”转换为“指针int”,接收的值foo是数组第一个元素的地址:

void foo(int *a)
{
  // do stuff with a[i]
}

表达式a[i]被解释为*(a + i); 我们找到后面的第i' 个元素的地址a并取消引用结果。

这是一种冗长的说法,您将[]在函数的参数上使用运算符,就好像它们是常规数组一样。

将数组返回给主函数时,如何在不清理内存的情况下返回结果函数?

不太清楚你在这里的意思。请注意,以下代码不起作用:

int *foo(int *a1, int *a2)
{
  int a3[SOME_SIZE];

  // copy elements from a1 and a2 to a3;

  return a3;
}

一旦foo退出,数组a3就不存在了;该内存被系统回收,因此您返回的指针值不再有效。你有三个选择:

首先,您可以将目标数组作为第三个参数传递:

int main(void)
{
  int arr1[N];
  int arr2[M];
  int arr3[K];
  ...
  foo(arr1, arr2, arr3);
  ...
}

void foo(int *a1, int *a2, int *result) { ... }

前提是result指向一个足够大的数组以容纳您找到的所有元素(它应该与两个源数组中较大的一个一样大)。如果您不想搞乱动态内存管理,这就是要走的路。

其次,可以在函数中动态分配目标数组:

int main(void)
{
  int a1[M];
  int a2[N];
  int *a3;
  ...
  a3 = foo(a1, a2);
  ...
  free(a3);
}

int *foo(int *a1, int *a2)
{
  int *result = malloc(sizeof *result * SOME_SIZE);
  ...
  if (element_in_both_arrays())
    result[n++] = element_from_both_arrays();
  ...
  return result;
}

完成后,您必须记住释放内存。

最后,您可以将目标数组声明为全局变量(即在文件范围内)。我不打算举一个例子,因为你不想那样做。

每当您将数组传递给函数或返回动态分配的缓冲区时,您确实需要将数组大小作为单独的参数传递。通常,仅根据指针值无法确定数组中有多少元素。您可以使用标记值,但它们只告诉您数组的逻辑大小,而不是其物理大小。例如:

char buffer[1024] = "foo";

逻辑大小buffer为 3(字符串的长度),但其物理大小为 1 KB。

于 2013-02-19T22:56:36.430 回答
0
  1. 要知道数组的长度,您需要将长度作为参数传递,或者您需要在数组中有一个特殊值,表示它是最后一项。

  2. 如果你传递一个数组,你传递的是一个指向该数组的指针。如果不清楚,也许您应该包含一些代码。

  3. 如果将数组传递给函数,则对数组所做的任何更改将对调用方法可见。没有必要返回任何东西。

于 2013-02-19T22:30:39.403 回答
0

For 1:函数的调用者应该知道每个数组的长度。允许将此信息传递到函数中。您可以选择使用标记值来指示有效元素的结束,但您必须确保该函数的所有用户都知道此约定并遵循它。

对于 2:数组名称将降级为指针类型,其值为数组第一个元素的地址(在大多数情况下)。不需要做任何特别的事情来实现这一点。

对于 3:您可以让调用者提供一个指向将输出复制到其中的内存的指针。或者,一个数组可以由函数动态分配,但是调用者需要知道释放这个内存。

/* Finds elements common to both a and b, and copies them to c. The c out
   parameter is assumed to be at least as large as the smaller of the a_sz
   and b_sz. Returns the number of elements copied into c. */
int find_in_common (const int *a, size_t a_sz, const int *b, size_t b_sz,
                    int *c)
{
    /* ... */
}
于 2013-02-19T22:33:43.410 回答