1
votes

Pourquoi ne puis-je pas copier un tableau dans un autre?

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 commentaires

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 de string .


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 dans argv seront valides et dans la portée pour la durée du programme, utilisez simplement des pointeurs à la place.


4 Réponses :


4
votes

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 ou strdup ou quelque chose de similaire, alors oui. Utiliser strncpy 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 comme strlcpy , qui est disponible sur les systèmes POSIX, mais cela ne fait pas partie du standard C. Si vous utilisez strlcpy au lieu de strncpy , 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>


1 commentaires

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.



1
votes

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.


2 commentaires

" 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



0
votes

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.


0 commentaires

0
votes

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:

https://godbolt.org/z/lag4uL


0 commentaires