qwertyuiop123456789
qwertyuiop123456789

Reputation: 41

Why can't I copy one array to another?

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?

Upvotes: 1

Views: 145

Answers (4)

Alper
Alper

Reputation: 141

In C, an array name is not an L-value expression. Hence you can not use it in an assignment statement. To make a copy of a character array, you can either use a for statement or strcpy function, which is declared in string.h header file.

Upvotes: 0

0___________
0___________

Reputation: 67476

The short answer is: because it is. In the C language only structures and unions are copied by value with one exception:

Initialization of the array

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

and the compiled code:

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"

Structures and unions are copied by the value sothe assignment copies the whole structure to another.

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

and the code:

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"

you can play with it yourself:

https://godbolt.org/z/lag4uL

Upvotes: 0

klutt
klutt

Reputation: 31306

Why doesn't this work?

Because that's simply how it works in C. Trying with string = argv[1] (without *) would be a better guess, but you cannot copy arrays with simple assignments.

Do I actually need to use loops to iterate through each element and do everything the long way?

Unless you are prepared to use functions like strcpy, strncpy or strdup or something similar, then yes. Using strncpy in your code would look like this:

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

The last line is to make sure that string is terminated. Clunky? Yes, it is. There are better functions in some compilers like strlcpy, which is available on POSIX systems, but it's not a part of the C standard. If you use strlcpy instead of strncpy you can skip the last line.

If you're planing to do a lot of string copying and don't have a compiler supporting strlcpy, it might be a good idea to write your own implementation (good practice) or just copy an existing one. Here is one I found:

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

Source: https://android.googlesource.com/platform/system/core.git/+/brillo-m7-dev/libcutils/strlcpy.c

Upvotes: 4

jazz64
jazz64

Reputation: 339

In the main function in C argv is a vector to strings which are arrays of characters themself. So argv is a pointer to a pointer (like **char).

Your code assigns a reference to one pointer (to first argument).

char* string = argv[1]; would do it. To copy the whole string (array of characters) use strcpy. To copy all arguments use memcpy.

But usually in a C program you do not copy arguments, just use references to them.

Upvotes: 1

Related Questions