如何在C中复制数组数组? (字符串数组到另一个字符串数组)

时间:2012-08-20 02:57:04

标签: c arrays string multidimensional-array

我正在做Zed Shaw的 Learn C The Hard Way 课程。在练习11中,在额外学分问题#2中,他问道:

  
      
  1. 使用i--从argc开始并倒数到0,使这些循环向后计数。你可能需要做   一些数学使数组索引正常工作。

  2.   
  3. 使用while循环将值从argv复制到状态。

  4.   

我试试:

#include <stdio.h>

int main(int argc, const char *argv[]){

    int i = argc - 1;
    while(i >= 0){
        printf("arg %d: %s\n", i, argv[i]);
        i--;
    }

    char *states[] = {
        "California", "Oregon",
        "Washington", "Texas"
    };

    int num_states = 4;
    i = num_states - 1;
    while( i >= 0){
        printf( "state %d, %s\n", i, states[i]);
        i--;
    }

    i = 0;
    while(i < argc && i < num_states){
        int j = 0;
        while( (states[i][j++] = argv[i][j++]) != '\0' ){
            i++;
        }
        states[i][j] = '\0';
    }

    i = num_states - 1;
    while( i >= 0){
        printf( "state %d, %s\n", i, states[i]);
        i--;
    }

    return 0;
}

我得到Segmentation Fault。我知道你不能在C中复制数组,它们是const指针或类似的东西(或者我读过)。这就是我尝试逐个字符复制的原因:

while(i < argc && i < num_states){
    int j = 0;
    while( (states[i][j++] = argv[i][j++]) != '\0' ){
        i++;
    }
    states[i][j] = '\0';
}

然而它不起作用。我该怎么做?编译时编译器给出了这个警告:

$ make ex11
cc -Wall -g    ex11.c   -o ex11
ex11.c: In function ‘main’:
ex11.c:26:28: warning: operation on ‘j’ may be undefined [-Wsequence-point]

我不明白为什么它说j未定义。 valgrind说:

$ valgrind ./ex11 this is a test
==4539== Memcheck, a memory error detector
==4539== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==4539== Using Valgrind-3.8.0 and LibVEX; rerun with -h for copyright info
==4539== Command: ./ex12 this is a test
==4539== 
arg 4: test
arg 3: a
arg 2: is
arg 1: this
arg 0: ./ex11
state 3, Texas
state 2, Washington
state 1, Oregon
state 0, California
==4539== 
==4539== Process terminating with default action of signal 11 (SIGSEGV)
==4539==  Bad permissions for mapped region at address 0x400720
==4539==    at 0x4005F1: main (ex11.c:26)
==4539== 
==4539== HEAP SUMMARY:
==4539==     in use at exit: 0 bytes in 0 blocks
==4539==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==4539== 
==4539== All heap blocks were freed -- no leaks are possible
==4539== 
==4539== For counts of detected and suppressed errors, rerun with: -v
==4539== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Segmentation fault

[编辑1] 切换了我的代码

int i = 0;
while( i < argc && i < num_states ){
    states[i] = argv[i];
    i++;
}

它确实有效,但编译器给了我一个警告。此外,我在发布此问题之后意识到我的上一个:

while( (states[i][j++] = argv[i][j++]) != '\0' ){
    i++;
}

是完全错的。因为j++每个循环执行两次,并且i++应该在外循环中的该循环之外。而且正如下面的评论中所提到的,我尝试使用数组数组进行的逐字节复制不起作用,因为我实际上有指针数组。

那就是说,如果没有编译器的警告,有没有办法可以做到这一点?

2 个答案:

答案 0 :(得分:2)

一个问题(导致SEGV的问题)是states是一个char *的数组,你用一堆字符串文字(const char *来初始化它)。所以你至少应该在那条线上收到警告。当你尝试写入字符串常量(在只读内存中)时,这会引起你的兴趣。

现在,如果你真的想要一次一个字节地将字符串从argv复制到states(而不仅仅是复制指针 - 例如states[i] = argv[i]),你需要确保states[i][j]是可写的。你可以通过使states一个字符数组数组,而不是一个指向字符的指针数组来做到这一点:

char  states[][16] = {
    "California", "Oregon",
    "Washington", "Texas"
};

当然,这些都是固定大小的数组,所以你需要担心溢出它们,但是你已经遇到了遍历状态数组本身的问题。

答案 1 :(得分:0)

我刚刚完成了这项练习,并且在完成复制后正在进行更多的复制研究(如Zed建议的那样)。这就是我做的,没有问题。

    i = 0;
    num_states = NELEMS(states);

    while(i < argc  && i <= num_states) {
            states[i] = argv[i];
            i++;
    }