【问题标题】:program in C is crashing when more memory is used当使用更多内存时,C 中的程序崩溃
【发布时间】:2023-03-30 09:09:01
【问题描述】:

我必须做一个 C 语言的学校作业小程序,它将读取标准输入并打印一些标准输出。更具体地说,它是关于读取数字并对其进行排序。

(可以跳过,只是为了理解代码) 输入的第一行应确定将有多少行数字。第二行是下一行数字的数量。第三行是具体数字。第四行是下一行的数字数量,依此类推,直到达到 K 行。限制为 0

示例 输入:

  1. 2 //表示将有2个数字序列(行)及其对应的数量
  2. 3 //第一个序列会有3个数字
  3. 5 99912 45 //第一个序列
  4. 6 //在第二个序列中会有6个数字
  5. 9489498 22131 0 521313 7988956 5 //第二个序列

输出:

0 5 5 45 22131 99912 521313 7988956 9489498

所以我已经完成了一个工作程序,但它似乎不稳定,具有更高的值。但是我无法确定程序究竟何时何地失败。在我的电脑上,我测试了所有可能的最大值,并在合理的时间内返回了正确的输出,但在完成测试的学校服务器上,它无法处理高值并失败。

有一件事,程序应该只使用 C,而不是 C++,但我不太确定它们之间的差异,而且由于我使用的是 C++ 编译器,所以我的代码可能不仅仅是原始 C。

我是一个 C 初学者,这对我来说就像“Hello world”,所以请你快速浏览一下代码并说出可能导致不稳定的原因吗?谢谢

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

int main(void) {    
    int k, n, i, y, x, index = 0;
    int *numbers = (int*) malloc(100000000 * sizeof(int));
    if(numbers == NULL){
        exit(1);
    }
    scanf("%d", &k);
    for (x = 0; x < k; x++) {
        y = 0;
        scanf("%d", &n);
        while(scanf("%d", &i) > 0){
            numbers[index++] = i;
            if(++y == n){
                break;
            }
        }
    }
    for(y = 0;y < index;y++){   //find and print all 0's, because later I will use 0 as a
                                //already used (printed) element in array and ignore it      
        if(numbers[y] == 0){
            if(y == index-1){
                printf("0");
            }else{
                printf("0 ");
            }
        }
    }
    int smallest, smallestIndex;
    for(x = 0;x < index;x++){   //print all other numbers in ascending order
        smallest = 0;
        for(y = 0;y < index;y++){  //find current smallest number
            if((numbers[y] < smallest || smallest == 0) && numbers[y] != 0){
                smallest = numbers[y];
                smallestIndex = y;
            }
        }
        numbers[smallestIndex] = 0;
        if(smallest > 0){
            if(x == index-1){
                printf("%d", smallest);
            }else{
                printf("%d ", smallest);
            }
        }
    }
    free(numbers);
    numbers = NULL;
    return 0;
}

【问题讨论】:

  • 快速浏览后,您似乎只使用了 C 而不是 // cmets。 C 的当前版本现在可能支持这一点,我不确定。
  • 另外,你能告诉我们更多关于你的学校服务器发生故障的细节吗?您收到错误消息吗?如果是这样,请将其复制并粘贴到此处,以便我们帮助您找出解决方案。
  • 您不需要预先分配那么多内存。搜索realloc 函数。
  • 我无法获得有关崩溃原因的更多信息,服务器的测试工具只返回测试了哪些值以及使用这些值的测试是否成功。我会试试 realloc 函数
  • 也许崩溃的是测试工具。

标签: c memory


【解决方案1】:

根据您提供的信息,我认为这只是服务器上的资源限制。服务器只是内存不足,您的malloc() 失败。我建议你调试或这样做:

if(numbers == NULL){
    printf("malloc() failed\n");
    exit(1);
}

【讨论】:

  • 那么 malloc 函数工作正常,它总是返回指向该数组的指针,我认为没有任何限制。正如我所说,这是与输入相关的问题,并且输入值很小,它可以正常工作,因此在分配后某处失败
  • 你错了。问题是他没有分配足够的内存。
【解决方案2】:

打印初始零的代码可疑:

for(y = 0;y < index;y++){   //find and print all 0's, because later I will use 0 as a
                            //already used (printed) element in array and ignore it      
    if(numbers[y] == 0){
        if(y == index-1){
            printf("0");
        }else{
            printf("0 ");
        }
    }

假设您有一个以 0 作为最后一个元素的序列(例如 1 2 3 4 5 0);我猜这段代码只会打印0,后面没有空格,后面的代码会打印1 2 3 4 5,所以你会得到类似01 2 3 4 5的东西。

我了解您希望输出尽可能美观,即末尾没有空格。另请注意,输出末尾的换行符 (\n) 可能很好。

【讨论】:

  • 谢谢,你是对的,我正在考虑它,但懒得修复它。我想我会一直打印“0”,因为在每个序列中至少应该有一个非空数字。
【解决方案3】:

我重写了您程序的开头部分,以使您走上正确的道路。这应该对您有所帮助,但我不能确定,因为我真的不知道是什么导致您的程序崩溃。

这实现了realloc 函数,它应该使您的程序比现在更加高效。如果您不知道realloc 是什么,您可以阅读herehere

#include <stdio.h>
#include <stdlib.h>
#define BUFFER 256                                                  //for memory management         

int main(void) 
{    
    int k, n, i, y , x, index = 0, bff;                             //declare integer 'bff' and set it to BUFFER
    int *numbers = NULL, *tmp;                                      //declare a pointer (numbers) for allocated memory, and a pointer (tmp) for the realloc function

    if(!(numbers = malloc(BUFFER * sizeof(int))))                   //allocate space for 'bff' integers
    {
        exit(1);                                                    //allocation failed
    }
    scanf("%d", &k);
    for (x = 0; x < k; x++) 
    {
        scanf("%d", &n);
        while(scanf("%d", &i) > 0)
        {
            if(bff <= index)                                        //if the size of index grows larger than the amount of space we allocated
            {
                bff += BUFFER;                                      //increase the size of bff by BUFFER
                if(!(tmp = realloc(numbers, bff * sizeof(int))))    //resize our allocated memory block using the tmp pointer 
                {
                    free(numbers);                                      //allocation failed so free already allocated memory
                    exit(1);                                        //and terminate the program
                }
                numbers = tmp;                                      //make numbers point to the same location as tmp
                numbers[index++] = i;                               
                if(++y == n) break;
            }
        }
    }
    .
    .
    .
    free(numbers);
    return 0;
}

请记住,使用 realloc 有更有效的方法。我刚刚在这里发布了这个让你走上正轨。祝你好运!

【讨论】:

  • 为什么以 256 为单位递增?每个序列都以该序列中的元素数量开始。将该号码用于realloc 不是更好吗?这样就只需要k allocs。
  • 我刚刚发布了这个,以便 OP 可以感受 realloc 功能。他们希望如何实施它是他们的选择。但我个人更喜欢每次将分配空间的大小增加固定数量。
【解决方案4】:

您分配了错误的内存量。规范规定 每个 序列可以包含 1000 万个值,而您分配的数量是固定的。最多可能有 k*1000 万 个输入值,而您无法知道您分配的数量是否足够。

正如m0skit0所指出的,问题也可能是由于过度分配造成的。

要解决问题,您应该分配所需的内存量,不多也不少。 使用为每个序列提供的序列长度来执行此操作。 另外,您需要检查mallocrealloc 的返回值。如果返回值为NULL,则分配失败,您应该打印错误消息和exit

【讨论】:

  • 它分配了100000000(1亿)个值,而不是1000万(看代码)
  • 我的错误。我的回答的本质仍然是正确的——他分配了错误的内存量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多