Нужна помощь с malloc в программировании на C. Он выделяет больше места, чем ожидалось - PullRequest
4 голосов
/ 03 февраля 2011

Позвольте мне предварить это, сказав, что я новичок, и я нахожусь в начальном классе C в школе.

Я пишу программу, которая требовала от меня использования malloc, а malloc выделяет в 8 раз больше места, чем я ожидаю, во всех случаях.Даже когда только для malloc (1), это выделение 8 байтов вместо 1, и я не понимаю, почему.

Вот мой код, с которым я тестировал.Это должно позволять вводить только один символ плюс escape-символ.Вместо этого я могу ввести 8, поэтому он выделяет 8 bytes вместо 1, это так, даже если я просто использую целое число в malloc().Пожалуйста, игнорируйте переменную x, она используется в реальной программе, но не в этом тесте.:

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


int main (int argc ,char* argv[]){

    int x = 0;
    char *A = NULL;
    A=(char*)malloc(sizeof(char)+1);
    scanf("%s",A);
    printf("%s", A);
    free(A);
    return 0;
}

Ответы [ 9 ]

6 голосов
/ 03 февраля 2011
 A=(char*)malloc(sizeof(char)+1);

собирается выделить как минимум 2 байта (sizeof (char) всегда равен 1).Я не понимаю, как вы определяете, что он выделяет 8 байтов, однако malloc разрешено выделять больше памяти, чем вы просите, просто никогда.

Тот факт, что вы можете использовать scanf для записи более длинной строки в память, указанную буквой A, не означает, что эта память выделена.Он перезапишет все, что там есть, что может привести к сбою вашей программы или получению неожиданных результатов.

5 голосов
/ 03 февраля 2011

malloc выделяет столько памяти, сколько вы просили.

Если вы можете прочитать больше выделенных байтов (используя scanf), это потому, что scanf читает также из вашей памяти: переполнение буфера.

Вы должны ограничить данные, которые scanf может прочитать следующим образом:

scanf( "%10s", ... ); // scanf will read a string no longer than 10
3 голосов
/ 03 февраля 2011

Я пишу программу, которая требовала меня использовать malloc и malloc выделяет 8x место, которое я ожидаю во всех случаев. Даже когда только для malloc (1), это это выделение 8 байтов вместо 1, и я не понимаю, почему.

Теоретически, то, как вы делаете вещи в программе, не выделяет 8 bytes.

Вы все еще можете ввести 8 байтов (или любое количество байтов), потому что в C нет проверки, что вы все еще используете допустимое место для записи.

То, что вы видите, это Undefined Behaviour, и причина этого в том, что вы пишете в памяти, что не должны. В вашем коде нет ничего, что могло бы остановить программу после использования выделенных вами n байт.

Вы можете получить Seg Fault сейчас, или позже, или никогда. Это неопределенное поведение. То, что это работает, не означает, что это правильно.

Теперь ваша программа действительно может выделить 8 байтов вместо 1.

Причина этого заключается в выравнивании

Одна и та же программа может выделять другой размер на другой машине и / или в другой операционной системе.

Кроме того, поскольку вы используете C, вам не нужно разыгрывать. См. this для начала.

2 голосов
/ 03 февраля 2011

В вашем коде нет ограничений на количество данных, которые вы можете загрузить с помощью scanf, что приводит к переполнению буфера (недостаток безопасности / сбой).Вы должны использовать строку формата, которая ограничивает объем считываемых данных одним или двумя байтами, которые вы выделяете.Функция malloc, вероятно, выделит дополнительное пространство для округления размера, но вы не должны на это полагаться.

1 голос
/ 03 февраля 2011

использование malloc или создание буфера в стеке выделит память в словах.

В 32-битной системе размер слова составляет 4 байта, поэтому при запросе

A=(char*)malloc(sizeof(char)+1);

(что по существу A=(char*)malloc(2);

система фактически выдаст вам 4 байта. На 64-битной машине вы должны получить 8 байт.

То, как вы используете scanf, опасно, так как переполнит буфер, если строка больше выделенного размера, оставляя уязвимость переполнения кучи в вашей программе. scanf в этом случае попытается вставить строку любой длины в эту память, поэтому использование ее для подсчета выделенного размера не будет работать.

1 голос
/ 03 февраля 2011

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

1 голос
/ 03 февраля 2011

На какой системе вы работаете? Если он 64-битный, возможно, что система выделяет наименьшую возможную единицу, которую она может. 64 бита, 8 байтов.

РЕДАКТИРОВАТЬ: просто примечание интереса:

char *s = malloc (1);

Вызывает выделение 16 байт на iOS 4.2 (Xcode 3.2.5).

0 голосов
/ 03 февраля 2011

scanf понятия не имеет, насколько велик целевой буфер.Все, что он знает, это начальный адрес буфера.C не проверяет границы, поэтому, если вы передадите ему адрес буфера размером 2 символа и введете строку длиной 10 символов, scanf запишет эти дополнительные 8 символов в память после конца буфера,Это называется переполнением буфера, которое является распространенным вредоносным программным средством.По какой-то причине шесть байтов, следующих сразу за вашим буфером, не являются «важными», поэтому вы можете ввести до 8 символов без видимых вредных последствий.

Вы можете ограничить число символов, читаемых в вызове scanf, включив явную ширину поля в спецификатор преобразования:

scanf("%2s", A);

, но вам все равно нужно убедиться, чтоцелевой буфер достаточно велик, чтобы вместить эту ширину.К сожалению, невозможно динамически указать ширину поля, как в printf:

printf("%*s", fieldWidth, string);

, поскольку %*s означает что-то совершенно другое в scanf (в основном, пропуститьпо следующей строке).

Вы можете использовать sprintf для построения строки формата:

sprintf(format, "%%%ds", max_bytes_in_A);
scanf(format, A);

, но вы должны убедиться, что буфер format достаточно широк для хранения результата и т. Д., И т. Д.и т. д.

Именно поэтому я обычно рекомендую fgets() для интерактивного ввода.

0 голосов
/ 03 февраля 2011

Если вы введете 8, если просто выделите 2 байта sizeof(char) == 1 (unless you are on some obscure platform), и вы напишите свой номер этому символу. Затем на printf будет выведен номер, который вы там сохранили. Так что, если вы сохраните число 8, оно отобразит 8 в командной строке. Это не имеет никакого отношения к количеству выделенных символов. Если, конечно, вы не искали в отладчике или где-то еще, что он действительно выделяет 8 байтов.

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