Разпределяне на памет на езика char* C

Това ли е правилният начин за разпределяне на памет към char*.

char* sides ="5";

char* tempSides;

tempSides = (char*)malloc(strlen(inSides) * sizeof(char));

person boom    schedule 04.06.2010    source източник
comment
@brickner какво ще кажете за това в strlen, strlen(inSides) + 1   -  person boom    schedule 04.06.2010


Отговори (7)


почти. Низовете завършват с NULL, така че вероятно искате да отделите допълнителен байт за съхраняване на байта NULL. Тоест, въпреки че sides е дълъг 1 символ, той наистина е 2 байта: {5,'\0'}.

Така че би било:

tempSides = (char *)malloc((strlen(sides)+1)*sizeof(char));

и ако искате да го копирате в:

strcpy(tempSides, sides);
person Claudiu    schedule 04.06.2010
comment
Имате предвид '\0', когато казвате NULL. '\0' е NULL, а не NULL. - person George Phillips; 04.06.2010
comment
Имайте предвид, че умножаването по sizeof(char) не е необходимо; sizeof(char) се определя като 1. - person caf; 04.06.2010
comment
@caf: Вярно, но пропускането му прави по-трудно адаптирането на кода към wchar_t или TCHAR, когато е необходимо - ако няма умножения, има риск да забравите да използвате едно. - person sharptooth; 04.06.2010
comment
Не забравяйте да проверите за NULL преди strcpy - person R Samuel Klatchko; 04.06.2010
comment
@sharptooth: Умножаването по sizeof *tempSides би било най-добре, ако се притеснявате да преминете към wchar_t по-късно. - person jamesdlin; 04.06.2010
comment
@George Phillips: Строго погледнато, имате предвид „нулев знак“. nul е ASCII псевдоним за нулевия знак; терминът 'nul' не се появява никъде в стандарта C. - person dreamlax; 04.06.2010
comment
@R Samuel Klatchko: как предлагате да се направи такава проверка и какви биха били възможните последствия? Ако няма \0 след въвеждането, и strlen(), и strcpy ще се провалят по същия начин като предложената от вас проверка. - person MSalters; 04.06.2010
comment
@MSalters: той имаше предвид проверка на върнатата стойност malloc. - person jweyrich; 04.06.2010
comment
Бих използвал strncpy вместо strcpy. В този случай знаем, че буферът е достатъчно голям, така че strcpy е ОК. Предпочитам обаче да избягвам strcpy във ВСИЧКИ случаи. Разходите са толкова малки, че е малко вероятно да видите реална разлика в производителността. - person daotoad; 05.06.2010

Забележи, че:

  1. Низовете завършват с нула (\0) и strlen() не го брои;
  2. По дефиниция sizeof(char) е 1 (байт), така че не е задължително;
  3. Ако използвате C (не C++) компилатор, няма нужда да го прехвърляте към char *;

Така че това би било:

char *tempSides = malloc(strlen(inSides) + 1);

И все пак, ако искате да дублирате съдържанието на inSides, можете да използвате strdup, напр.:

char *tempSides = strdup(inSides);
if (tempSides != NULL) {
    // do whatever you want...
    free(tempSides);
}
person jweyrich    schedule 04.06.2010

Както беше посочено, вие сте пропуснали да разпределите място за завършващия NUL символ. Но също така исках да посоча няколко други неща, които могат да направят кода ви по-сбит.

По дефиниция sizeof(char) винаги е 1, така че можете да съкратите своя ред за разпределение до:

tempSides = (char*)malloc(strlen(inSides) + 1);

Друго нещо е, че това изглежда, че правите, за да дублирате низа. Има вградена функция, която прави това вместо вас:

tempSides = strdup(inSides);

Това обработва получаването на дължината, разпределянето на правилния брой байтове и копирането на данните.

person R Samuel Klatchko    schedule 04.06.2010

Има проблем с това. tempSides ще посочи неинициализиран блок памет с размер 1. Ако възнамерявате да копирате страничния низ в tempSides, тогава ще трябва да разпределите размер с един байт по-дълъг, за да задържите нулевия терминатор за низа. Стойността, върната от strlen(), не включва нулевия терминатор в края на низа.

person Vagrant    schedule 04.06.2010

Не наистина. Както други вече отбелязаха, трябва да отделите място за терминатора NUL.

В допълнение, обикновено не трябва да кастирате връщането от malloc. Може да прикрие грешка, при която сте забравили да #include правилната заглавка. Умножаването по sizeof(char) също е безсмислено, тъй като стандартите (както C, така и C++) определят sizeof(char) винаги да бъде 1.

И накрая, всяко обаждане до malloc трябва да включва тест на резултата. Бих увил всичко във функция:

char *dupe_string(char const *string) { 
    char *temp;
    if (NULL!=(temp=malloc(strlen(string)+1)))
        strcpy(temp, string);
    return temp;
}
person Jerry Coffin    schedule 04.06.2010

Умножаването на броя на елементите по sizeof(char) е въпрос на лично предпочитание, тъй като sizeof(char) винаги е 1. Въпреки това, ако правите това за последователност, по-добре използвайте типа на указателя на получателя, за да определите размера на елемента, вместо изрично да указвате типа. И не предавайте резултата от malloc

tempSides = malloc(strlen(inSides) * sizeof *tempSides);

Разбира се, когато работите с низове, завършващи с нула, трябва да запомните да отделите допълнително място за завършващия символ нула. Няма начин да се каже дали намерението ви е да направите tempSides низ, завършващ с нула в този случай, така че не мога да кажа дали имате нужда от него.

person AnT    schedule 04.06.2010
comment
Няма начин? По-добре да използва низове, завършващи с нула, когато извиква strlen... Ако той използва своя собствена strlen, тогава наистина не искам да бъда програмистът по поддръжката след него. ;) - person Secure; 04.06.2010
comment
@Secure: Това означава само, че inSides е завършен с нула. В кода няма индикация, че tempSides също трябва да завършва с нула. - person AnT; 04.06.2010

Правилният начин за разпределяне на динамична памет към tempSides е както е показано по-долу:

char* sides ="5";
char* tempSides;
tempSides = (char*)malloc((strlen(sides) + 1) * sizeof(char));

char* съхранява данни от низ, подобно на char[]. Низовете са null (\0) прекратени. Така че допълнителен един байт трябва да бъде разпределен за null символно съхранение.

Динамично разпределеният блок памет трябва да бъде освободен с помощта на free(), след като употребата му приключи. Ако не бъде освободен, ще се случи изтичане на памет.

free(tempSides);

Когато паметта бъде освободена, трябва да се присвои NULL, за да се предотврати това да бъде висящ указател.

tempSides = NULL;
person pkthapa    schedule 16.11.2016