Динамическое выделение целочисленного массива с 1 миллиардом элементов в C - PullRequest
1 голос
/ 14 апреля 2020

В C я пытаюсь создать целочисленный массив с 1 000 000 000 (1 миллиард) элементов. Я пытался использовать;

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <time.h>

#define population 1000000000

int numberOfHandshaking;

int main(int argc, char **argv) {
    printf("******************************\n");
    printf("     FRIEND CIRCLE QUERIES\n");
    printf("******************************\n\n");

    FILE *fPointer;
    fPointer = fopen("C:\\Users\\ASUS\\Desktop\\AdvProTech2\\uebung_6\\Ass13in.txt", "r");

    fscanf(fPointer, "%d", &numberOfHandshaking); // Reads the first line
    printf("numberOfHandshakings: %d\n", numberOfHandshaking);

    int *persons = malloc((population + 1) * sizeof(int));

    for (int i = 0; i < 127; i++) {
        printf("persons[%d]= %d \n", i, persons[i]);
    }

    printf("\n\n\n");
    return 0;
}

, это не выдает ошибку при компиляции, но вылетает при попытке добраться до элементов. Может кто-нибудь мне помочь?

Ответы [ 3 ]

2 голосов
/ 14 апреля 2020

При работе с такими смешными числами скомпилируйте вашу программу в 64 бита. Или просто напишите лучший код, потому что я могу гарантировать, что вам не нужен этот массив, выделенный таким образом.

0 голосов
/ 15 апреля 2020

Прежде всего, вы не говорите, в какой архитектуре вы пробуете этот подход. Во-вторых, вы не говорите, какую операционную систему вы используете. Вы только говорите, что пытаетесь malloc(3) массив из одного миллиарда int с.

Подумайте дважды: один массив из 1 000 0000 001 int элементов имеет размер 4 000 000 004. Если вы пытаетесь обработать это в 32-битной архитектуре, вы просите систему выделить все пространство виртуальной памяти (которая составляет 4 ГБ) только для вашего массива. Скорее всего, у вас очень жесткий лимит, который мешает вам выделять такой объем памяти.

В 64-битной архитектуре у вас достаточно адресов для обработки этого, но, опять же, возможно, ваша операционная система откажется создавать одно непрерывное отображение такого размера (или объем виртуальной памяти, которую ваша система может обрабатывать). Наиболее вероятным является то, что вы не сможете получить эту память. Я вижу, что вы запускаете это в windows (по пути, который вы используете для имени файла), поэтому, скорее всего, вы даже не сможете проверить, сколько памяти вы можете обработать для процесса.

Я проверил вашу программу в 64-битная архитектура FreeBSD, в которой у меня есть следующие ограничения (я должен признать, что я немного их подправил, чтобы справиться с вашей проблемой для моей учетной записи пользователя, поскольку обычному пользователю в многопользовательской системе никогда не предоставляются такие ограничения по умолчанию):

$ ulimit -a
number of pseudoterminals            (-P) unlimited
socket buffer size       (bytes, -b) unlimited
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) 33554432
file size               (blocks, -f) unlimited
max kqueues                     (-k) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 230121
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 524288
cpu time               (seconds, -t) unlimited
max user processes              (-u) 12042
virtual memory          (kbytes, -v) unlimited
swap size               (kbytes, -w) unlimited

(как вы можете видеть, я имею максимальный предел размера сегмента данных в 33 Гб, поэтому, если я запросил массив из 10 миллиардов элементов, я потерпел неудачу и должен сказать, что это ограничение навязано ядром, я не могу поднять его - даже как root)

  • Когда я это сделал, я получил SIGSEGV, потому что указатель файла, возвращенный fopen(3), дал NULL (файл не существует, еще одна вещь, которую вы не проверяете в своей программе), поэтому программа была прервана по вызову fscanf(3). Примечание. Необходимо проверить возвращаемые значения вызовов на наличие ошибок.
  • После этого я смог запустить (и действительно выделить миллиардный массив --plus one-- elements). ) без каких-либо проблем. Программа FreeBSD запускается за 0,001 с от начала до конца, так как ей не нужно выделять всю эту память в одном блоке (действительно, ей не нужно выделять все, так как вы используете только первые 126 элементов массива, поэтому действительно, вы выделите только одну страницу такой памяти, 504 байта памяти.
$ pru
*****************************************
     THIS WAS FRIEND CIRCLE QUERIES
*****************************************

numberOfHandshakings: 99885
persons[0]= 0 
persons[1]= 0 
persons[2]= 0 
[...]
persons[123]= 0 
persons[124]= 0 
persons[125]= 0 
persons[126]= 0 



Затем я установил максимальный объем виртуальной памяти 4 Гб и повторил тест:

$ pru
*****************************************
     THIS WAS FRIEND CIRCLE QUERIES
*****************************************

numberOfHandshakings: 99885
malloc failed: Cannot allocate memory

на этот раз результат ulimit -a был:

$ ulimit -a
number of pseudoterminals            (-P) unlimited
[... same as before ]
max user processes              (-u) 12042
virtual memory          (kbytes, -v) 4194304 <<<<<< 4Gb virtual memory.
swap size               (kbytes, -w) unlimited

Ваша программа после внесенных в нее изменений, чтобы иметь возможность обрабатывать ошибки, возвращаемые вызовами fopen() и malloc() было:

#include <ctype.h>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define population 1000000000

int numberOfHandshaking;

int main(int argc, char **argv)
{
    printf("*****************************************\n");
    printf("     THIS WAS FRIEND CIRCLE QUERIES\n");
    printf("*****************************************\n\n");

    FILE *fPointer;
    fPointer =
        fopen("Ass13in.txt", /* I changed this, my apologies */
            "r");

    if (fPointer == NULL) {
        printf("couldn't open file: %s\n", strerror(errno));
        exit(1);
    }

    fscanf(fPointer, "%d", &numberOfHandshaking); // Reads the first line
    printf("numberOfHandshakings: %d\n", numberOfHandshaking);

    int *persons = malloc((population+1) * sizeof(int));

    if (persons == NULL) {
        printf("malloc failed: %s\n", strerror(errno));
        exit(1);
    }

    for (int i=0; i<127; i++){
        printf("persons[%d]= %d \n", i, persons[i]);
    }

    printf("\n\n\n");
    return 0;
}

и все работает нормально !!:)

ПРИМЕЧАНИЕ:

В вашей программе вы #include файлы, которые вам не нужны к. Это:

#include <ctype.h>
#include <math.h>
#include <time.h>
0 голосов
/ 14 апреля 2020

Если вы не знаете необходимый размер буфера до времени выполнения, при выделении памяти предпочтительны меньшие куски, чем очень очень большие куски, где высока вероятность сбоя из-за недостатка доступной непрерывной памяти.

Начните с calloc/malloc, затем используйте realloc:

// return '*str' after number of bytes realloc'ed to 'size'
static char * ReSizeBuffer(char **str, unsigned int size)
{
    char *tmp=NULL;

    if(!(*str)) return NULL;

    if(size == 0)
    {
        free(*str);
        return NULL;
    }

    tmp = (char *)realloc((char *)(*str), size);
    if(!tmp)
    {
        free(*str);
        return NULL;
    }
    *str = tmp;

    return *str;
}
...