Почему я не могу скопировать один массив в другой? - PullRequest
1 голос
/ 15 июня 2019
int main(int argc, char *argv[])
{
    char string[100];
    string = *argv[1];
}

Почему это не работает?Мне действительно нужно использовать циклы для итерации каждого элемента и делать все долгий путь?

Ответы [ 4 ]

4 голосов
/ 15 июня 2019

Почему это не работает?

Потому что это просто, как это работает в C. Попытка с string = argv[1] (без *) была бы лучшим предположением, но вы не можете скопироватьмассивы с простыми присваиваниями.

Нужно ли мне на самом деле использовать циклы для перебора каждого элемента и делать все долгий путь?

Если вы не готовы использовать такие функции, какstrcpy, strncpy или strdup или что-то подобное, тогда да.Использование strncpy в вашем коде будет выглядеть так:

char string[100];
strncpy(string, argv[1], sizeof(string));
string[sizeof(string) - 1] = 0;

Последняя строка должна убедиться, что string завершен.Неуклюжим?Да, это.В некоторых компиляторах есть улучшенные функции, такие как strlcpy, который доступен в системах POSIX, но не является частью стандарта C.Если вы используете strlcpy вместо strncpy, вы можете пропустить последнюю строку.

Если вы планируете много копировать строки и не имеете компилятора, поддерживающего strlcpy, это может привести кХорошей идеей будет написать собственную реализацию (хорошая практика) или просто скопировать существующую.Вот один, который я нашел:

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 */
}

Источник: https://android.googlesource.com/platform/system/core.git/+/brillo-m7-dev/libcutils/strlcpy.c

0 голосов
/ 15 июня 2019

Короткий ответ: потому что это так.На языке C только структуры и объединения копируются по значению с одним исключением:

Инициализация массива

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);
}

и скомпилированного кода:

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"

Структуры и объединения копируются по значению, так что назначение копирует всю структуру в другую.

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);
}

и код:

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"

Вы можете играть с ним самостоятельно:

https://godbolt.org/z/lag4uL

0 голосов
/ 15 июня 2019

В C имя массива не является выражением L-значения.Следовательно, вы не можете использовать его в операторе присваивания.Чтобы сделать копию массива символов, вы можете использовать либо инструкцию for, либо функцию strcpy, которая объявлена ​​в заголовочном файле string.h.

0 голосов
/ 15 июня 2019

В главной функции в C argv - вектор к строкам, которые сами являются массивами символов.Так что argv - это указатель на указатель (например, **char).

Ваш код назначает ссылку на один указатель (на первый аргумент).

char* string = argv[1]; сделает это.Чтобы скопировать всю строку (массив символов), используйте strcpy.Чтобы скопировать все аргументы, используйте memcpy.

Но обычно в программе на Си вы не копируете аргументы, просто используйте ссылки на них.

...