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] achar
tö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
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 asomething_else
nagyobb, mintsizeof(buf)
. Általában az utolsó karaktertbuf[sizeof(buf)-1] = 0
állítom be, hogy megvédjem ettől, vagy ha abuf
nulla inicializálású, akkor használja azsizeof(buf) - 1
mint másolat hossza. - Használja a
strlcpy
vagy astrcpy_s
vagy akársnprintf
ha kell. - Javítva. Sajnos erre nincs egyszerű hordozható módszer, hacsak nincs luxusa dolgozni a legújabb fordítókkal (
strlcpy
éssnprintf
nem érhetők el közvetlenül az MSVC-n legalább a megrendelések és astrcpy_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 astrlen
helyett, amikor ‘ aggódik a memória miatt. Ehhez hasonlóan ellenőrizheti astrcpy
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 azstring[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áltchar *
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 achar[]
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é achar* 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 nemconst
, 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, haconst char *s = "literal";
- ” És általában a ” fájlban az asdf ” állandó, ezért konst. ” – Ugyanez az érvelés egy
const
t igényelne aint n = 42;
oldalon, mert42
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 amit1 + 1
2
-nek értékel. Ha az a program, amelyet fentebb linkeltem , aEFGH
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ó).
strncpy
ritkán a helyes válaszchar[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ásaseprate
ésseparate
között, ha a méretet nem frissítik.strlen()
fájlból származik, nem tartalmazza a null karaktert, aMAX_MONTH_LENGTH
achar 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.