【问题标题】:Why am I getting weird values when I copy integers into a new dynamic array?当我将整数复制到新的动态数组中时,为什么会得到奇怪的值?
【发布时间】:2020-10-02 23:01:27
【问题描述】:

我用 C 语言编写了一个函数,用于将一个 int 数组中的所有素数复制到一个大小相同的新动态数组中。

这是函数:

int *cpy(int arr[], int size){
    int *newArr = malloc(size * sizeof(int));
    for (int i = 0; i < size; i++) {
        if (isPrime(arr[i])) {
            *(arr + i) = arr[i];
        }
    }
    return newArr;
}

这是驱动代码

int arr[SIZE] = { 129, 73, 87, 2, 923, 6743, 983, 23 };
int *newArr = cpy(arr, SIZE);
printf("Question 4: ");
printIntArr(newArr);
free(newArr);

注意SIZE 是我用来存储所有原型/宏的头文件中定义为 20 的宏

由于某种原因,我得到以下输出:

Question 4: 12261328 12255424 285212761 39925 33619971

我不明白我做错了什么。我对 C 比较陌生,所以对于愚蠢的错误,我很抱歉

编辑:我尝试了第一个评论解决方案,但我得到了:

Question 4: 129 6684864 87 33150 923

【问题讨论】:

  • *(arr + i) = arr[i]; -> *(newArr + i) = arr[i];
  • 我试过了,但我得到了Question 4: 129 6684864 87 33150 923
  • 您需要第二个索引来跟踪将条目添加到newArr。您需要告诉调用者添加了多少条目。
  • 我不确定你的意思。 void printIntArr(int* arr) 使用 SIZE 在我的头文件中定义为 8。它知道接收到的数组的大小,但新数组中的元素看起来像是垃圾值。
  • 是的,但您的newArr 不一定用SIZE 值填写。该函数的重点是只用素数填充它。因此,根据定义,它可能包含比原始数组更少的值。此外,出于类似原因,您不能使用 i 作为 newArray 的索引,因为并非所有这些索引都将用于新数组。

标签: c malloc sizeof


【解决方案1】:

您需要在循环中添加第二个索引:

int* cpy(int arr[], int size){
        int* newArr = malloc((size + 1) * sizeof(int));
        for (int i = 0, j = 0; i < size; i++){
              if (isPrime(arr[i])){
                    *(newArr + j) = arr[i];
                     j++;
               }
         }
         newArr[j] = 0; // add a NULL at the end
         return newArr;
  }

如果你不这样做,你将有一个数组,其中包含内存中未初始化的值

例子:

输入:1 3 6 9 13

输出:1 3 72742729 92652729 13

原因:跳过了 6 和 9,留下了一个垃圾值。

【讨论】:

  • 如果arr 中的所有值都是素数,则最终的newArr[j] = 0; 将具有未定义的行为。您应该分配一个额外的条目以避免这种情况:int *newArr = malloc((size + 1) * sizeof(int)); 不清楚新数组中的条目数应该如何传递回调用者。
【解决方案2】:
int* cpy(int arr[], int size){
    int* newArr = malloc(size * sizeof(int));
    for (int i = 0; i < size; i++){
        if (isPrime(arr[i])){
            *(arr + i) = arr[i]; // <---------------- ? why you use arr here?
        }
    }
    return newArr;
}

尝试:

int* cpy(int arr[], int size){
    int* newArr = malloc(size * sizeof(int));
    memset(newArr, 0, sizeof(size * sizeof(int)); // <----- initialize newArr
    for (int i = 0; i < size; i++){
        if (isPrime(arr[i])){
            *(newArr + i) = arr[i]; // <--- ? I think you want to use newArr here
        }
    }
    return newArr;
}

也许你也可以在 newArr 上添加一个 memset:

memset(newArr, 0, sizeof(size * sizeof(int));

memset 将使用默认值 (0) 初始化内存的特定区域 (newArr),用于特定数量的字节 (size * sizeof(int)),这样您就不会在那里找到“垃圾”(垃圾是非初始化值)

【讨论】:

    【解决方案3】:

    您的行为未定义,因为 cpy 函数不会向目标数组写入任何内容:*(newArr + j) = arr[i]; 只是将 arr[i] 复制到自身。

    还有一个问题:您只复制了一些条目,因此您应该为目标数组使用单独的索引并更改函数原型以返回存储在那里的元素数量。

    这是修改后的版本:

    #include <stdio.h>
    #include <stdlib.h>
    
    int isPrime(int n) {
        if (n % 2 == 0)
            return n == 2;
        for (int i = 3;; i += 2) {
            int quo = n / i;
            int rem = n % i;
            if (quo < i)
                return 1;
            if (rem == 0)
                return 0;
        }
    }
    
    void printIntArr(int *arr, int n) {
        for (int i = 0; i < n; i++) {
            printf("%d ", arr[i]);
        }
        printf("\n");
    }
    
    int *filter_primes(int arr[], int size, int *nprimes) {
        int *newArr = malloc(size * sizeof(int));
        int j = 0;
        for (int i = 0; i < size; i++) {
            if (isPrime(arr[i])) {
                newArr[j] = arr[i];
                j++;
            }
        }
        *nprimes = j;
        return newArr;
    }
    
    int main() {
        int arr[SIZE] = { 129, 73, 87, 2, 923, 6743, 983, 23 };
        int n;
        int *newArr = filter_primes(arr, SIZE, &n);
        printf("Question 4: ");
        printIntArr(newArr, n);
        free(newArr);
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-23
      • 2010-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-12
      • 2020-01-08
      相关资源
      最近更新 更多