【问题标题】:0 in The Array is Causing a Semantic Error. How to Overcome?数组中的 0 导致语义错误。如何克服?
【发布时间】:2022-01-23 20:57:14
【问题描述】:

问题是编写一个程序从用户那里读取一个整数数组并将其传递给一个函数,该函数接受两个数组 - 第一个数组包含从用户获得的值,第二个数组作为空数组。目的是将原始数组中存在的偶数的索引附加到空数组中,并返回原始数组中存在的偶数个数。

如果输入是:

Enter number of elements: 5
Enter element [1]: 0
Enter element [2]: 1
Enter element [3]: 2
Enter element [4]: 3
Enter element [5]: 4

然后输出显示:

37945345.

这是空数组的第一个元素内的垃圾值。

这是代码:

#include <stdio.h>

int evenIndices(int origArr[], int emptyArr[]) {

    int i = 0, j = 0;
    int evenCount = 0;

    while (origArr[i] != '\0') {
        if (origArr[i] % 2 == 0) {
            emptyArr[j] = i;
            evenCount ++;
            j++;
        }
        i++;
    }

    return evenCount;
}

int main() {

    int numOfElts;
    printf("Enter number of elements: ");
    scanf("%d", &numOfElts);
    int arr[numOfElts];

    for (int i = 0; i < numOfElts; i++) {
        printf("Enter element [%d]: ", i + 1);
        scanf("%d", &arr[i]);
    }

    arr[numOfElts] = '\0';

    int indexArr[numOfElts];
    int evenCount = evenIndices(arr, indexArr);

    printf("There are %d even numbers. \n", evenCount);
    printf("*** Indices With Even Numbers in Original Array *** \n");

    for (int i = 0; i < evenCount - 1; i++) {
        printf("%d, ", indexArr[i]);
    }

    printf("%d. \n", indexArr[evenCount - 1]);

    return 0;
}

此代码适用于数组中除 0 以外的所有数字。如果输入 0,则函数假定它与 '\0' 相同并退出循环。有什么办法解决这个问题?

【问题讨论】:

  • 那是因为'\0'的值 0——这里没有假设,就是这么定义的。更好的解决方案是将数组的长度传递给函数,而不是使用一些标记值
  • arr[numOfElts] = '\0' 写入越界。

标签: arrays c undefined-behavior zero function-definition


【解决方案1】:

"将它传递给一个接受两个数组的函数"

要传递数组,必须以某种方式包含大小信息,因为 C 中的数组参数会衰减为简单的指针,从而丢失所有数组大小信息。以下方法使用 VLA 参数格式,即在原型中的数组本身之前定义要传递的数组的大小...

从以下位置更改原型:

int evenIndices(int origArr[], int emptyArr[]);

收件人:

int evenIndices(int x, int y, int origArr[x], int emptyArr[y]);

然后将其传递为:

int evenCount = evenIndices(numOfElts, numOfElts, arr, indexArr);

或者,由于本例中两个数组大小相同,可以在原型中只定义int x

 int evenIndices(int x, int origArr[x], int emptyArr[x]);

然后将其传递为:

 int evenCount = evenIndices(numOfElts, origArr, emptyArr);

【讨论】:

  • 好的。请注意,问题陈述指出,只能传递两个数组。
  • @AbdullahSheriff - 这里的例子确实传递了两个数组。我不确定我是否理解您的担忧。如果您不想包含数组大小,那么被调用的函数将无法确定它们的大小,因为数组在作为参数传递时会衰减为仅指针。
  • 谢谢。明白了。
【解决方案2】:

对于初学者来说,这个赋值语句

arr[numOfElts] = '\0';

调用未定义的行为,因为存在数组之外的内存访问,因为数组的有效索引范围是[0, numOfElts)

删除此语句。

函数evenIndices 应该声明为

int evenIndices( const int origArr[], int n, int emptyArr[]);

也就是说你需要传递原始数组中的元素个数。并且第一个参数应该用限定符const 声明,因为传递的数组在函数内没有改变。

while循环中的条件

while (origArr[i] != '\0') {

没有意义。用户可以输入 0 作为源数组的有效值。

其中一个变量jevenCount 是多余的。

函数可以通过以下方式定义

int evenIndices( const int origArr[], int n, int emptyArr[])
{
    int evenCount = 0;
    
    for ( int i = 0; i < n; i++ )
    {
        if ( origArr[i] % 2 == 0 ) emptyArr[evenCount++] = i;
    }

    return evenCount;
}      

函数的调用方式如下

int evenCount = evenIndices( arr, numOfElts, indexArr );

注意如果函数返回0那么这段代码sn-p

for (int i = 0; i < evenCount - 1; i++) {
    printf("%d, ", indexArr[i]);
}

printf("%d. \n", indexArr[evenCount - 1]);

将产生无效的输出。无需拆分 for 循环。而是写

for (int i = 0; i < evenCount; i++) {
    printf("%d, ", indexArr[i]);
}

putchar( '\n' );

【讨论】:

  • [0, numOfElts) 是正确的,但可能更普遍地理解为 索引范围是: 0 - numOfElts-1
【解决方案3】:

您正在尝试使用'\0' 作为哨兵。因此,您不能将'\0' 或“0”('\0'0)作为有效值。我建议您使用INT_MIN 作为哨兵。那么你的可接受输入范围将是 2^32-1 到 -(2^32-1),这会很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-29
    • 2021-11-14
    • 2015-09-03
    • 1970-01-01
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多