A karakter [] inicializálása egy karakterlánccal szó szerint rossz gyakorlat?

Olvastam egy szálat, amelynek címe “strlen vs sizeof” a CodeGuru-n , és div id = “22f0f376d3”>

az egyik válasz kijelenti, hogy “mindenképpen [sic] rossz gyakorlat inicializálni [sic] achartömböt karakterlánccal. “

Ez igaz, vagy csak az ő (bár” elit tag “) véleménye van?


Itt az eredeti kérdés:

#include <stdio.h> #include<string.h> main() { char string[] = "october"; strcpy(string, "september"); printf("the size of %s is %d and the length is %d\n\n", string, sizeof(string), strlen(string)); return 0; } 

igaz. a méretnek a hossznak plusz 1 igennek kell lennie?

ez az a kimenet

the size of september is 8 and the length is 9

a méretnek biztosan 10-nek kell lennie. Ez hasonlít a karakterlánc méretének kiszámításához, mielőtt az strcpy megváltoztatná után.

Valami baj van a szintaxissal, vagy mi van?


Itt van a válasz :

Mindenesetre rossz gyakorlat inicializálni egy char tömböt egy karakterlánccal. Tehát mindig tegye a következők egyikét:

const char string1[] = "october"; char string2[20]; strcpy(string2, "september"); 

Megjegyzések

  • Az első sorban vegye figyelembe a ” const ” t. Lehetséges, hogy a szerző c helyett + c-t feltételezett? A c ++ nyelven ” rossz gyakorlat “, mert a literálnak konstansnak kell lennie, és a legújabb c ++ fordító figyelmeztetést (vagy hibát) ad egy konst literál hozzárendeléséhez egy nem const tömbhöz.
  • @Andr é A C ++ a string literálokat konst-tömbként definiálja, mert ez az egyetlen biztonságos módszer velük. Ez a C nem ‘ t a probléma, tehát van egy társadalmi szabálya, amely érvényesíti a biztonságos dolgot
  • @Caleth. Tudom, inkább azzal akartam érvelni, hogy a válasz írója c ++ szempontból közelítette meg a ” rossz gyakorlatot “. / li>
  • @Andr é ez nem ‘ rossz gyakorlat a C ++ nyelven, mert ez nem ‘ ta gyakorolja , ez ‘ egyenesen felfelé írja a hibát. típushibának kell lennie a C-ben, de nem ‘ t, ezért rendelkeznie kell egy stílus útmutatóval, amely megmondja, hogy ” Ez ‘ tilos ”

válasz

Mindenesetre rossz gyakorlat inicializálni a char tömböt egy karakterlánccal.

A hozzászólás szerzője soha nem igazolja igazán, és a mondatot értetlennek tartom.

A C-ben (és ezt C-ként jelölte meg), hogy ” Nagyjából az egyetlen módja a char tömb tring inicializálásának string értékkel (az inicializálás különbözik a hozzárendeléstől). Írhat akár

char string[] = "october"; 

vagy

char string[8] = "october"; 

vagy

char string[MAX_MONTH_LENGTH] = "october"; 

Az első esetben a tömb mérete az inicializáló méretéből származik. A karakterlánc-literálokat a char tömbökként tárolják végződő 0 bájttal, így a tömb mérete 8 (“o”, “c”, “t”, “o”, “b”, “e”, “r”, 0). A második két esetben a tömb méretét a deklaráció részeként adjuk meg (8 és MAX_MONTH_LENGTH, bármi legyen is az eset).

Amit nem tudsz megtenni, olyasmit írsz, hogy

char string[]; string = "october"; 

vagy

char string[8]; string = "october"; 

stb. Az első esetben a string deklaráció hiányos , mert nincs megadva tömbméret, és nincs inicializáló, ahonnan a méretet átvehetjük. esetekben a = nem fog működni, mert a) egy tömb kifejezés, például string, nem feltétlenül lehet egy hozzárendelés célja, és b) a = operátor amúgy sincs meghatározva, hogy az egyik tömb tartalmát átmásolja a másikba.

Ugyanezen token segítségével nem írhat

char string[] = foo; 

ahol foo a char másik tömbje. Ez az inicializálási forma csak karakterláncokkal működik.

SZERKESZTÉS

Ezt módosítanom kell, hogy inicializálhasson is tömbök egy karakterlánc tárolására tömb stílusú inicializálóval, például

char string[] = {"o", "c", "t", "o", "b", "e", "r", 0}; 

vagy

char string[] = {111, 99, 116, 111, 98, 101, 114, 0}; // assumes ASCII 

de a szemen könnyebb használni a karakterláncokat.

SZERKESZTÉS 2

A A tömb tartalma t egy deklaráción kívül rendelheti hozzá, vagy a strcpy/strncpy -t (0 végű karakterláncokhoz), vagy a memcpy (bármely más típusú tömbhöz):

if (sizeof string > strlen("october")) strcpy(string, "october"); 

vagy

strncpy(string, "october", sizeof string); // only copies as many characters as will // fit in the target buffer; 0 terminator // may not be copied, but the buffer is // uselessly completely zeroed if the // string is shorter! 

Megjegyzések

  • strncpy ritkán a helyes válasz
  • @KeithThompson: nem értek egyet ezzel, csak a teljesség érdekében adtam hozzá ‘.
  • Felhívjuk figyelmét, hogy char[8] str = "october"; rossz gyakorlat. Szó szerint be kellett számolnom magam, hogy megbizonyosodjak arról, hogy ‘ nem volt-e túlcsordulás, és karbantartás közben megszakad … pl. a helyesírási hiba kijavítása seprate és separate között, ha a méretet nem frissítik.
  • Egyetértek a djechlinnel, a megadott okok miatt rossz gyakorlat. JohnBode ‘ válasza ‘ egyáltalán nem kommentálja a ” rossz gyakorlatot ” szempont (ami a kérdés fő része !!), csak elmagyarázza, hogy mit tehet vagy mit nem tehet a tömb inicializálásához.
  • Kisebb: As ‘ length ” érték, amely a (z) strlen() fájlból származik, nem tartalmazza a null karaktert, a MAX_MONTH_LENGTH a char string[] számára szükséges maximális méret megtartásához gyakran rosszul néz ki . IMO, MAX_MONTH_SIZE itt jobb lenne.

Válasz

Az egyetlen probléma, amire emlékszem, a literál karakterlánc hozzárendelése a char *:

char var1[] = "september"; var1[0] = "S"; // Ok - 10 element char array allocated on stack char const *var2 = "september"; var2[0] = "S"; // Compile time error - pointer to constant string char *var3 = "september"; var3[0] = "S"; // Modifying some memory - which may result in modifying... something or crash 

Vegyük például ezt a programot:

#include <stdio.h> int main() { char *var1 = "september"; char *var2 = "september"; var1[0] = "S"; printf("%s\n", var2); } 

Ez a platformomon (Linux) összeomlik, amikor megpróbál írni, csak olvashatóként megjelölt oldalra. Más platformokon előfordulhat, hogy “szeptember” -et nyomtat. / div>

De ez

char buf[32] = "May"; strncpy(buf, "September", sizeof(buf)); 

Utolsó megjegyzésként – nem használnám a strcpy egyáltalán:

char buf[8]; strcpy(buf, "very long string very long string"); // Oops. We overwrite some random memory 

Míg egyes fordítók biztonságos hívássá változtathatják, az strncpy sokkal biztonságosabb:

char buf[1024]; strncpy(buf, something_else, sizeof(buf)); // Copies at most sizeof(buf) chars so there is no possibility of buffer overrun. Please note that sizeof(buf) works for arrays but NOT pointers. buf[sizeof(buf) - 1] = "\0"; 

Megjegyzések

  • Még vannak ‘ A puffer túllépésének kockázata abban az strncpy -ben, mert nem ‘ t null véget vet a másolt karakterláncnak, amikor a something_else nagyobb, mint sizeof(buf). Általában az utolsó karaktert buf[sizeof(buf)-1] = 0 állítom be, hogy megvédjem ettől, vagy ha a buf nulla inicializálású, akkor használja az sizeof(buf) - 1 mint másolat hossza.
  • Használja a strlcpy vagy a strcpy_s vagy akár snprintf ha kell.
  • Javítva. Sajnos erre nincs egyszerű hordozható módszer, hacsak nincs luxusa dolgozni a legújabb fordítókkal (strlcpy és snprintf nem érhetők el közvetlenül az MSVC-n legalább a megrendelések és a strcpy_s nincsenek bekapcsolva * nix).
  • @MaciejPiechotka: Nos, hála istennek, Unix elutasította a microsoft által szponzorált k mellékletet.

Válasz

Elsősorban azért, mert nem fogod megadni a char[] egy változóban / konstrukcióban, amelyet könnyen használhat a programon belül.

A kódminta a linkről:

 char string[] = "october"; strcpy(string, "september"); 

A string 7 vagy 8 karakter hosszúságú a veremben. Nem tudom felidézni, hogy ez null-végű-e így vagy sem – az általad linkelt szál kijelentette, hogy .

A “szeptember” másolása a karaktersorozaton nyilvánvaló túllépés a memóriában.

Egy másik kihívás akkor jelentkezik, ha a string fájlt átadja egy másik függvénynek.így a másik függvény beírhatja a tömbbe. El kell mondania a másik függvénynek, hogy meddig van a tömb ez nem hoz létre túllépést. Átadhatja a string -t a strlen(), de a szál elmagyarázza, hogy ez hogyan robbanthat fel, ha a string nincs null-végű.

Jobban jársz rögzített méretű (lehetőleg konstansként definiált) karaktersorozat kiosztása, majd a tömb és a rögzített méret átadása a másik függvénynek. @John Bode megjegyzése (i) helyesek, és vannak módok ezeknek a kockázatoknak a mérséklésére. Ezek felhasználásához több erőfeszítést igényelnek az Ön részéről.

Tapasztalatom szerint az az érték, amelyet inicializáltam a A div id = “e010afea17”>

to általában túl kicsi ahhoz a többi értékhez, amelyet be kell helyeznem. Egy meghatározott konstans használata segít elkerülni ezt a problémát.


sizeof string megadja a puffer méretét (8 bájt); használja a kifejezés eredményét a strlen helyett, ha aggódik a memória miatt.
Hasonlóképpen ellenőrizheti a strcpy, hogy megnézze, a célpuffer elég nagy-e a forrás karakterlánchoz: if (sizeof target > strlen(src)) { strcpy (target, src); }.
Igen, ha át kell adnia a tömböt egy függvénynek, akkor ” át kell adnia a fizikai méretét is: foo (array, sizeof array / sizeof *array);. – John Bode

Megjegyzések

  • sizeof string megadja a puffer méretét (8 bájt); használja a kifejezés eredményét a strlen helyett, amikor ‘ aggódik a memória miatt. Ehhez hasonlóan ellenőrizheti a strcpy hívását, hogy meggyőződjön arról, hogy a célpuffer elég nagy-e a forrás karakterlánchoz: if (sizeof target > strlen(src)) { strcpy (target, src); }. Igen, ha át kell adnia a tömböt egy függvénynek, akkor ‘ át kell adnia a fizikai méretét is: foo (array, sizeof array / sizeof *array);.
  • @JohnBode – köszönöm, és ezek jó pontok. Megjegyzését beépítettem a válaszomba.
  • Pontosabban, a string tömb nevére való legtöbb utalás implicit átalakítást eredményez , a tömb első elemére mutatva. Ez elveszíti a tömbre vonatkozó információkat. A függvényhívás csak egy a sok összefüggés közül, amelyben ez megtörténik. char *ptr = string; egy másik. Erre még az string[0] is példa; az [] operátor mutatókon dolgozik, nem közvetlenül a tömbökön. Javasolt olvasmány: A comp.lang.c GYIK 6. szakasza.
  • Végül egy válasz, amely valójában a kérdésre utal!

Válasz

Az egyik dolog, amit egyik szál sem hoz fel, ez:

char whopping_great[8192] = "foo"; 

vs.

char whopping_great[8192]; memcpy(whopping_great, "foo", sizeof("foo")); 

Az előbbi ilyesmit fog tenni:

memcpy(whopping_great, "foo", sizeof("foo")); memset(&whopping_great[sizeof("foo")], 0, sizeof(whopping_great)-sizeof("foo")); 

Ez utóbbi csak a memcpy-t hajtja végre. A C szabvány ragaszkodik ahhoz, hogy ha egy tömb bármely részét inicializálják, akkor mindez az. Tehát ebben az esetben jobb, ha te magad csinálod. Úgy gondolom, hogy ez volt az, amire a treuss ért.

Biztosan

char whopping_big[8192]; whopping_big[0] = 0; 

jobb, mint bármelyik:

char whopping_big[8192] = {0}; 

vagy

char whopping_big[8192] = ""; 

ps bónuszpontokat tehetsz:

memcpy(whopping_great, "foo", (1/(sizeof("foo") <= sizeof(whopping_great)))*sizeof("foo")); 

fordítási idő elosztása nulla hibával, ha túlcsordulsz a tömbön.

Válasz

Úgy gondolom, hogy a “rossz gyakorlat” ötlet onnan származik, hogy ez az űrlap:

char string[] = "october is a nice month"; 

implicit módon egy strcpy-t készít a forrásgép kódjától a veremig.

Hatékonyabb csak az adott karakterláncra mutató linket kezelni. Mint például:

char *string = "october is a nice month"; 

vagy közvetlenül:

strcpy(output, "october is a nice month"); 

(de természetesen a legtöbb esetben kód ez valószínűleg nem számít “)

Megjegyzések

  • Nem ‘ t csak másolatot készítene ha megpróbálja módosítani? Azt gondolom, hogy a fordító ennél okosabb lenne
  • Mi a helyzet az olyan esetekkel, mint char time_buf[] = "00:00";, ahol ‘ puffert akar módosítani? A karakterlánc-literálissá inicializált char * az első bájt címére van állítva, így annak módosítási kísérlete meghatározatlan viselkedést eredményez, mert a literal ‘ karakterlánc tárolási módja ismeretlen (a megvalósítás definiálva), míg a char[] bájtjainak módosítása teljesen legális, mert az inicializálás a bájtokat a veremben lefoglalt írható helyre másolja. Mondhatni, hogy ‘ s ” kevésbé hatékony vagy ” rossz gyakorlat ” anélkül, hogy részletezné a char* vs char[] félrevezető.

Válasz

Soha nem igazán hosszú idő, de kerüld az inicializáló karaktert [] karakterláncra, mert a “string” a konst char *, és Ön hozzárendeli a char * -hoz. Tehát, ha átadod ezt a char [] -ot az adatmódosító módszernek, érdekes viselkedésed lehet.

Ahogy a dicséret mondta, kevertem egy kis char [] -ot char * -val, ez nem jó, mivel kissé eltérnek egymástól.

Nincs semmi baj az adatok char tömbhöz való hozzárendelésével, de mivel ennek a tömbnek az a célja, hogy “stringként” (char *) használja, könnyen el lehet felejteni, hogy ezt nem szabad módosítania. tömb.

Megjegyzések

  • Helytelen. Az inicializálás a literál karakterlánc tartalmát másolja a tömbbe. A tömb objektum nem ‘ t const hacsak nem így definiálja.(És a C karakterlánc-literálok nem const, bár a string-literál módosításának minden kísérlete meghatározatlan viselkedéssel rendelkezik.) char *s = "literal"; milyen viselkedésről ‘ beszél; ‘ jobb, ha const char *s = "literal";
  • ” És általában a ” fájlban az asdf ” állandó, ezért konst. ” – Ugyanez az érvelés egy const t igényelne a int n = 42; oldalon, mert 42 egy állandó.
  • Nem ‘ nem számít, hogy melyik gépen van ‘. A nyelvi szabvány garantálja, hogy a c módosítható. ‘ pontosan olyan erős garancia, mint amit 1 + 1 2 -nek értékel. Ha az a program, amelyet fentebb linkeltem , a EFGH nyomtatáson kívül mást is csinál, akkor ez nem megfelelő C megvalósítást jelez.
  • @Dainus: Az MSVC fordító rendelkezik egy ‘ karakterlánc-pooling ‘ nevű optimalizálással, amely a azonos karakterláncok csak olvasható szegmensbe, ha garantálni tudja, hogy használatuk csak olvasható. Kapcsolja ki az optimalizálást a ‘ normális ‘ viselkedés megtekintéséhez. FYI a ” Szerkesztés és folytatás ” megköveteli, hogy ez az opció be legyen kapcsolva. További információ itt: msdn.microsoft.com/en-us/library/s0s0asdt.aspx
  • szerintem Dainius ezt sokakban javasolja esetekben a hiba az, hogy magát a változót const char *const jelöléssel kell ellátni, hogy megakadályozzák a bájtok vagy maga a mutató módosítását, de sok esetben a programozók az egyiket vagy mindkettőt változtatható módon hagyják, lehetővé téve néhány futási kódot módosítsa azt, ami tipikus állandónak tűnik (de nem állandó).

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük