int main(int argc, char *argv[]) { char string[100]; string = *argv[1]; } Why doesn't this work? Do I actually need to use loops to iterate through each element and do everything the long way?
4 Réponses :
Pourquoi cela ne fonctionne-t-il pas?
Parce que c'est simplement ainsi que cela fonctionne en C. Essayer avec
string = argv [1]
(sans *) serait une meilleure estimation, mais vous ne pouvez pas copier des tableaux avec des affectations simples.Dois-je réellement utiliser des boucles pour parcourir chaque élément et faire tout le long du chemin?
À moins que vous ne soyez prêt à utiliser des fonctions telles que
strcpy
,strncpy
oustrdup
ou quelque chose de similaire, alors oui. Utiliserstrncpy
dans votre code ressemblerait à ceci:size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0) { while (--n != 0) { if ((*d++ = *s++) == '\0') break; } } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ }La dernière ligne est de s'assurer que
string
est terminé . Clunky? Oui c'est le cas. Il y a de meilleures fonctions dans certains compilateurs commestrlcpy
, qui est disponible sur les systèmes POSIX, mais cela ne fait pas partie du standard C. Si vous utilisezstrlcpy
au lieu destrncpy
, vous pouvez ignorer la dernière ligne.Si vous prévoyez de faire beaucoup de copie de chaînes et de ne pas le faire. t avoir un compilateur prenant en charge
strlcpy
, il peut être judicieux d'écrire votre propre implémentation (bonne pratique) ou simplement de copier une implémentation existante. En voici un que j'ai trouvé:char string[100]; strncpy(string, argv[1], sizeof(string)); string[sizeof(string) - 1] = 0;Source: https://android.googlesource.com/platform/system/core.git/+/brillo-m7-dev/libcutils/strlcpy.c a>
strncpy
écrira toujours n
octets, en complétant avec des zéros si la chaîne source est plus courte. strlcpy
ou une implémentation personnalisée de celui-ci, qui ne fait pas le remplissage, peut être préférable.
Dans la fonction principale en C, argv
est un vecteur de chaînes qui sont elles-mêmes des tableaux de caractères. Donc argv
est un pointeur vers un pointeur (comme ** char
).
Votre code attribue une référence à un pointeur (vers le premier argument).
char * string = argv [1];
le ferait. Pour copier la chaîne entière (tableau de caractères), utilisez strcpy
. Pour copier tous les arguments, utilisez memcpy
.
Mais en général, dans un programme C, vous ne copiez pas les arguments, utilisez simplement des références à eux.
" en C argv
est un vecteur de chaînes ", non c'est un tableau de pointeur vers le 1er caractère d'une "chaîne" en C .
Je l'ai écrit à partir de mes connaissances pratiques, mais vous pouvez trouver exactement mes mots par exemple: gnu.org/software/libc/manual/html_node/Program-Arguments.htm l
En C, un nom de tableau n'est pas une expression de valeur L. Par conséquent, vous ne pouvez pas l'utiliser dans une instruction d'affectation. Pour faire une copie d'un tableau de caractères, vous pouvez utiliser une instruction for ou une fonction strcpy, qui est déclarée dans le fichier d'en-tête string.h.
La réponse courte est: parce que c'est le cas. En langage C, seules les structures et les unions sont copiées par valeur à une exception près:
Initialisation du tableau
foo3: sub sp, sp, #16 push {r4, r5, r6, lr} mov r6, #100 sub sp, sp, #104 ldr r5, .L4 add ip, sp, #116 add r4, sp, #4 stmib ip, {r0, r1, r2, r3} mov r2, r6 mov r1, r5 mov r0, r4 bl memcpy mov r2, r6 mov r1, r5 ldr r0, .L4+4 bl memcpy add r1, sp, #20 mov r2, #84 add r0, sp, #136 bl memcpy ldm r4, {r0, r1, r2, r3} add sp, sp, #104 pop {r4, r5, r6, lr} add sp, sp, #16 b foo4 .L4: .word .LANCHOR0 .word b a: .ascii "This string literal will be copied before main star" .ascii "ts\000"
et le code compilé:
typedef struct { char str[100]; }string; string a = {.str = "This string literal will be copied before main starts"},b; void foo3(string c) { string g = a; b = a; foo4(g); }
Les structures et les unions sont copiées par la valeur de sorte que l'affectation copie la structure entière dans une autre.
foo: push {r4, lr} sub sp, sp, #320 mov ip, sp ldr lr, .L4 ldr r4, .L4+4 ldmia lr!, {r0, r1, r2, r3} stmia ip!, {r0, r1, r2, r3} ldmia lr!, {r0, r1, r2, r3} stmia ip!, {r0, r1, r2, r3} ldmia lr!, {r0, r1, r2, r3} stmia ip!, {r0, r1, r2, r3} ldm lr, {r0, r1} str r0, [ip], #4 strb r1, [ip] add r0, sp, #208 mov r2, #110 ldr r1, .L4+8 bl memcpy mov r1, r4 add r0, sp, #56 mov r2, #72 bl memcpy mov r2, #80 add r1, r4, #72 add r0, sp, #128 bl memcpy add r1, sp, #208 mov r0, sp bl foo1 add r1, sp, #128 add r0, sp, #56 bl foo2 add sp, sp, #320 pop {r4, pc} .L4: .word .LC2 .word .LANCHOR0 .word .LC3 .LC2: .ascii "This string literal will be copied! Test it yoursel" .ascii "f\000" .LC3: .ascii "This string literal will be copied as well But beca" .ascii "use it is much loger memcpy will be used! Test it y" .ascii "ourself\000"
et le code :
void foo(void) { char x[] = "This string literal will be copied! Test it yourself"; char z[] = "This string literal will be copied as well But because it is much loger memcpy will be used! Test it yourself"; float y[] = {1.0,2.0, 3,0,4.0,5.0,1.0,2.0, 3,0,4.0,5.0,1.0,2.0, 3,0,4.0,5.0}; long long w[] = {1,2,3,4,5,6,7,8,9,0}; foo1(x,z); // this functions are only to prevent the variable removal foo2(y,w); }
vous pouvez jouer avec vous-même:
Si vous recherchez la commodité, C n'est pas le langage à utiliser.
Remarque: les types sont différents. Mais même
string = argv [1];
est interdit.Cette affectation attribuera (probablement) le premier caractère de
argv [1]
au premier caractère destring
.Le langage ne le permet tout simplement pas, donc oui, vous devez utiliser des boucles (directement ou indirectement via des fonctions standard comme
strcpy
). Ou, étant donné que les chaînes dansargv
seront valides et dans la portée pour la durée du programme, utilisez simplement des pointeurs à la place.