C语言 是什么原因导致此函数有时不返回任何值?

k4ymrczo  于 2022-12-11  发布在  其他
关注(0)|答案(3)|浏览(206)

我有一个函数,它应该返回一个从2到 n 的素数数组,但有时它什么也不返回,只是说“exited with code=3221225477”,特别是如果我输入了一个大于3或4的值。当它工作时,它跳过数字5并打印“2 3 29541 7 11 ..."。
有人能指出它有什么问题吗?

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

int *primes_in_range(int stop){
    int *array_primes = malloc(sizeof(int));
    int size = 1;
    int aim;
    int prime;

    array_primes[0] = 2;

    for (int number = 3; number <= stop; number += 2){
        aim = sqrt(number);

        for (int index = 0; index < size; index++){
            prime = array_primes[index];

            if ((number % prime) == 0){
                break;
            }
            else if (prime >= aim){
                array_primes = realloc(array_primes, sizeof(int)*size);
                array_primes[size] = number;
                size += 1;
                break;
            }
        }
    }
    return array_primes;
}

int main(){
    int *result = primes_in_range(8);
    
    for (int i=0; i<8; i++) printf("%d\n", result[i]);
    free(result);

    return 0;
}

我在python中写了一个遵循相同算法的程序,它没有跳过任何数字,所以它一定是出于另一个原因,除非我遗漏了什么,否则它不工作。
我将在这里留下工作的python代码:

def primes_in_range(stop: int = None):
    prms = [2]

    for num in range(3, stop+1, 2):
        aim = num**0.5

        for prm in prms:
            if not num % prm:
                break
            elif prm >= aim:
                prms.append(num)
                break

    if stop >= 2:
        return prms
    else:
        return []

print(primes_in_range(13))
kpbwa7wx

kpbwa7wx1#

你需要在调用realloc之前**递增size变量,然后使用size - 1作为新值的索引。就目前而言,你的程序正在写入一个超出分配的缓冲区范围的值(array_primes[size]),这将导致未定义的行为(这将使程序崩溃... * 有时 *)。
此外,你在列表末尾看到的“奇怪”数字也是从分配的缓冲区之外读取的值,因为你总是假设有8个值(实际上没有)。要解决这个问题,在函数中添加另一个int*参数,该参数可以返回找到的素数的个数,并将其用作printf循环的终止符值:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

int* primes_in_range(int stop, int* found) {
    int* array_primes = malloc(sizeof(int));
    int size = 1;
    int aim;
    int prime;

    array_primes[0] = 2;

    for (int number = 3; number <= stop; number += 2) {
        aim = sqrt(number);

        for (int index = 0; index < size; index++) {
            prime = array_primes[index];

            if ((number % prime) == 0) {
                break;
            }
            else if (prime >= aim) {
                size += 1; // Increase size BEFORE reallocating!
                array_primes = realloc(array_primes, sizeof(int) * size);
                array_primes[size - 1] = number; // The last (new) entry is at index "n - 1"
                break;
            }
        }
    }
    *found = size; // So we know how many were found
    return array_primes;
}

int main() {
    int total = 0;
    int* result = primes_in_range(8, &total);

    for (int i = 0; i < total; i++) printf("%d\n", result[i]); // Stop at found number
    free(result);

    return 0;
}
vx6bjr1n

vx6bjr1n2#

array_primes = realloc(array_primes, sizeof(int)*size);
array_primes[size] = number;
size += 1;

这不是将元素追加到数组的方式。正确的版本可以是:

size += 1; // first increase the size
array_primes = realloc(array_primes, sizeof(int)*size); // realloc to new size
array_primes[size-1] = number; // access last element, as usual

同样,您正在返回一个数组,但调用方不知道它的大小。要么返回一个包含数组及其大小的结构,要么通过地址传递一个大小以填充(输出参数),该大小也可以用作最大大小。

jogvjijk

jogvjijk3#

正如@WeatherVane所指出的,你的mallocs/remallocs是错误的。就我个人而言,我会采取更直接的方法,使用一个单一的操作:

int *array_primes = calloc(stop+1, sizeof(int));

这在一开始就分配最坏情况的大小,有一个安全余量。realloc的效率非常低,而且在小尺寸的情况下使用它们是丑陋的。在这样的代码中所有处理realloc的额外指令()也会占用空间...所以即使简单的malloc()获取一点额外的内存,通过删除remallocs,您通常在内存游戏中仍然领先。()和支持代码。调试也更简单。
remalloc()的缺失使您可以真正简化循环。
如果由于某种原因遇到零,调用者也可能提前中断结果。经过几十年的编程,我对这种事情变得非常偏执。

相关问题