C Распределение памяти: почему недостаточно памяти (только 250 КБ) - PullRequest
2 голосов
/ 02 ноября 2009

У меня проблемы с выяснением причины, по которой моему .c-коду не удается выделить ~ 250К памяти. Вот код распределения:

struct IMAGE {
    int width, height, maxval;
    char **data;
};

void raiseError(char *msg)
{
    printf("%s", msg);
    getch();
    exit(1);
}

//...

IMAGE readPGM()
{
    IMAGE image;
    image.data = (char **) malloc(sizeof(char)*image.height);

    //..

    for (i=0; i<image.height; i++) {
        image.data[i] = (char *) malloc(sizeof(char)*image.width);
        if (image.data[i]=='\0') {
            printf("%d\n", i);
            raiseError("Not enough memory!..");
        }
    }

    //..
}

//..

Программа завершается, когда я = 116. image.width и image.height здесь равны 500, поэтому я хочу, чтобы здесь было выделено 500x500 = 250000 байт. Но 116x500 = 58000 байт выделяются по максимуму. Итак, есть ли что-то, что ограничивает это? Что-то не так с моим кодом? Я публикую полный источник ниже, на всякий случай, если это необходимо. Идея состоит в том, чтобы прочитать файл PGM в структуру IMAGE, обработать его и переписать в другой файл. Как вы можете сказать, он еще не завершен, потому что я не мог найти способ выделить больше памяти.

#include<stdio.h>
#include<conio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<alloc.h>
struct IMAGE {
    int width, height, maxval;
    char **data;
};

void raiseError(char *msg)
{
    printf("%s", msg);
    getch();
    exit(1);
}

char *toString(int num)
{
    char sign = 0;
    if (num<0) {
        sign = -1;
        num*=-1;
    }
    int numLen = 1;
    if (sign<0) {
        numLen++;
    }
    int tmpNum = num;
    while (tmpNum>9) {
        tmpNum /= 10;
        numLen++;
    }
    char *result = (char *)malloc(sizeof(char)*(numLen+1));
    result[numLen] = '\0';
    char ch;
    while (num>9) {
        ch = (num%10)+'0';
        num /= 10;
        result[numLen-1] = ch;
        numLen--;
    }
    result[numLen-1] = num + '0';

    if (sign<0)
        result[0] = '-';
    return result;
}

int toInteger(char *line)
{
    int i=strlen(line)-1;
    int factor = 1;
    int result = 0;
    while (i>=0) {
        result += factor*(line[i]-'0');
        factor *= 10;
        i--;
    }
    return result;
}

char *getNewParam(FILE *fp)
{
    char ch = 'X';
    char *newParam;
    newParam = (char*) malloc(1);
    newParam[0] = '\0';
    int paramSize = 0;
    while (!isspace(ch)) {
        ch = fgetc(fp);
        if (!isspace(ch)) {
            if (ch=='#') {
                while (fgetc(fp)!='\n');
                continue;
            }
            paramSize++;
            newParam = (char *) realloc(newParam, paramSize+1);
            newParam[paramSize-1] = ch;
        }
    }
    newParam[paramSize] = '\0';
    return newParam;
}

IMAGE readPGM()
{
    FILE *fp;
    IMAGE image;
    //Open the file.
    fp = fopen("seeds2.pgm","r+b");
    if (fp=='\0')
        raiseError("File could not be opened!..");

    //Check if it is a raw PGM(P5)
    char *line;
    line = getNewParam(fp);
    if (strcmp(line, "P5")!=0)
        raiseError("File is not a valid raw PGM(P5)");
    int paramCount = 0;
    int *pgmParams;
    pgmParams = (int *)malloc(sizeof(int)*3);
    while (paramCount<3) {
        line = getNewParam(fp);
        pgmParams[paramCount++] = toInteger(line);
    }
    int pixelSize;
    if (pgmParams[2]>255)
        pixelSize = 2;
    else
        pixelSize = 1;

    image.width =pgmParams[0];
    image.height =pgmParams[1];
    image.maxval =pgmParams[2];
    free(pgmParams);
    image.data = (char **) malloc(sizeof(char)*image.height);
    int i,j;
    long sum = 0;
    for (i=0; i<image.height; i++) {
        image.data[i] = (char *) malloc(sizeof(char)*image.width);
        sum += sizeof(char)*image.width;
        if (image.data[i]=='\0') {
            printf("%d\n", i);
            raiseError("Not enough memory!..");

        }
    }
    for (i=0; i<image.height; i++) {
        for (j=0; j<image.width; j++) {
            fread(&image.data[i][j], sizeof(char), image.width, fp);
        }
    }
    fclose(fp);

    return image;
}

void savePGM(IMAGE image)
{
    FILE *fp = fopen("yeni.pgm", "w+b");
    fprintf(fp, "P5\n%s\n%s\n%s\n",
        toString(image.width), toString(image.height), toString(image.maxval));
    int i,j;
    for (i=0; i<image.height; i++) {
        for (j=0; j<image.width; j++) {
            fwrite(&image.data[i][j], sizeof(char), 1, fp);
        }
    }
    fclose(fp);
}

int main()
{
    clrscr();
    IMAGE image = readPGM();
    //process
    savePGM(image);
    getch();
    return 0;
}

Ответы [ 3 ]

12 голосов
/ 02 ноября 2009

Ответ на ваш вопрос содержится в добавленном вами комментарии. Вы используете (античный) 16-битный компилятор реального режима x86. 16-разрядная виртуальная машина может адресовать всего 1 МБ памяти, из которых только 640 КБ обычно доступны программам и используются совместно с ОС.

[редактировать в ответ на комментарий Паксдиабло]

В дополнение к этим ограничениям архитектура сегментированной адресации также порождает ряд моделей памяти , где всего 64 КБ могут быть ограничением для определенных областей памяти.

Также аргумент для malloc () имеет тип size_t, который в данном случае может быть только 16-битным - вам следует проверить. Я вспоминаю использование варианта с именем halloc () для больших выделений. Но если не использовать расширитель DOS, все еще существует ограничение в 640 КБ.

[конец редактирования]

Существует ряд гораздо более совершенных и бесплатных современных 32-битных компиляторов. Дамп античный. Я предлагаю VC ++ Express Edition

Кроме этого строго:

if(image.data[i]=='\0')

должно быть

if(image.data[i]==0)

или

if(image.data[i]==NULL)

Как это случается, это будет работать в любом случае, но технически вы проверяете нулевой указатель, а не символ NUL.

12 голосов
/ 02 ноября 2009

Я не собираюсь читать весь этот код - это яркий пример того, как вы должны привести минимальный пример для воспроизведения проблемы - но эта строка:

image.data = (char **) malloc(sizeof(char)*image.height);

неверно. Он должен иметь sizeof(char*). Заявление в письменном виде должно возвращать char*, но вы приводите его к char**.

FWIW, в моей системе sizeof(char) возвращает 1, а sizeof(char*) возвращает 4, потому что char - это один байт, а char* - указатель (или 32-разрядное слово). Таким образом, вы фактически выделили 1/4 того, что вы, вероятно, намеревались выделить.

1 голос
/ 02 ноября 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...