【问题标题】:Cannot copy strings from pointer array with strcpy in C? [duplicate]无法在C中使用strcpy从指针数组复制字符串? [复制]
【发布时间】:2018-01-18 20:01:37
【问题描述】:

我正在做一个练习,其中字符指针数组用作存储单词的一种方式。我不明白为什么我不能使用“strcpy”将单词“hoi”复制到主函数中数组的第二个元素。当我编译代码时,我在 CodeBlocks 中收到消息“程序已停止工作”。

函数“numberOfWordsInDict”和“printDict”工作正常。

提前致谢。

int numberOfWordsInDict(char **dict)
{
    int i, cnt = 0;
    for(i = 0; i < 10; i++)
    {
        if(dict[i] != NULL)
        {
            cnt++;
        }
    }
    return cnt;
}

void printDict(char **dict)
{
    int i = 0;
    printf("Dictionary:\n");
    if(numberOfWordsInDict(dict) == 0)
    {
        printf("The dictionary is empty.\n");
    } else
    {
        for(i = 0; i < 10; i++)
        {
            printf("- %s\n", dict[i]);
        }
    }
}

int main()
{
    char *dict[10] = {
            "aap", "bro ", "jojo", "koe", "kip", 
            "haha", "hond", "    drop", NULL,NULL};

    char *newWord1 = "hoi";
    printDict(dict);
    strcpy(dict[1], newWord1);
    printDict(dict);

    return 0;
}

【问题讨论】:

  • dict[1] 指向字符串文字的第一个字符。修改 strcpy(dict[1], newWord1) 所做的字符串文字会产生未定义的行为。
  • 非常感谢大家!
  • 这是一个非常常见的常见问题解答。如果您查看“字符串”下方的Stack Overflow C FAQ,则有几个规范帖子可用于进一步阅读/关闭重复。

标签: c undefined-behavior strcpy string-literals


【解决方案1】:

您需要在 RW 内存中保留存储空间并将文字复制到那里。您不必手动操作:)

#define MAXDICTSIZE 25

int numberOfWordsInDict(char dict[][MAXDICTSIZE], int dictsize)
{
    int i, cnt = 0;
    for (i = 0; i < dictsize; i++)
    {
        if (strlen(dict[i]))
        {
            cnt++;
        }
    }
    return cnt;
}

void printDict(char dict[][MAXDICTSIZE], int dictsize)
{
    int i = 0;
    printf("Dictionary:\n");
    if (numberOfWordsInDict(dict, dictsize) == 0)
    {
        printf("The dictionary is empty.\n");
    }
    else
    {
        for (i = 0; i < dictsize; i++)
        {
            if(strlen(dict[i]))printf("- %s\n", dict[i]);
        }
    }
}

在 main() 中的某处

char dict[10][MAXDICTSIZE] = {
    "aap", "bro ", "jojo", "koe", "kip",
    "haha", "hond", "    drop", "","" };

char *newWord1 = "hoi";
printDict(dict, sizeof(dict)/sizeof(dict[1]));
strcpy(dict[1], newWord1);
printDict(dict, sizeof(dict) / sizeof(dict[1]));

【讨论】:

    【解决方案2】:

    数组dict 是一个指向字符串字面量的指针数组。

    在此声明中

    strcpy(dict[1],newWord1);
    

    您正试图将一个字符串文字复制到另一个字符串文字中。

    字符串文字在 C 和 C++ 中是不可修改的。任何修改字符串字面量的尝试都会导致程序的未定义行为。

    来自 C 标准(6.4.5 字符串文字)

    7 不确定这些数组是否不同,前提是它们的 元素具有适当的值。 如果程序试图 修改这样的数组,行为未定义。

    如果要在其元素中复制字符串文字或动态分配的字符数组的一维数组,则应声明二维字符数组。

    程序可以如下所示

    #include <stdio.h>
    #include <string.h>
    
    #define N   9
    
    size_t numberOfWordsInDict( char dict[][N] )
    {
        size_t n = 0;
    
        while ( *dict[n] ) ++n;
    
        return n;
    }
    
    void printDict( char dict[][N] )
    {
        printf("Dictionary:\n");
    
        size_t n = numberOfWordsInDict( dict );
        if ( n == 0 )
        {
            printf("The dictionary is empty.\n");
        } 
        else
        {
            for ( size_t i = 0; i < n; i++ )
            {
                printf( "- %s\n", dict[i] );
            }
        }
    }
    
    int main(void) 
    {
        char dict[10][9] = 
        {
            "aap", "bro ", "jojo", "koe", "kip", "haha", "hond", "    drop"
        };
        char *newWord1 = "hoi";
    
        printDict(dict);
        strcpy(dict[1], newWord1);
        printDict(dict);
    
        return 0;
    }
    

    程序输出是

    Dictionary:
    - aap
    - bro 
    - jojo
    - koe
    - kip
    - haha
    - hond
    -     drop
    Dictionary:
    - aap
    - hoi
    - jojo
    - koe
    - kip
    - haha
    - hond
    -     drop
    

    或者您可以使用可变长度数组。

    请记住,根据 C 标准,不带参数的函数 main 应声明为

    int main( void )
    

    【讨论】:

    • 详细信息:C 未指定“字符串文字是不可修改的”。尝试这样做是UB。很好,你已经强调了这个的 UB。
    • @Vlad 来自莫斯科,您的代码是 UB。 char dict[10][9] = { "aap", "bro ", "jojo", "koe", "kip", "haha", "hond", " drop" }; 然后你迭代 size_t numberOfWordsInDict( char dict[][N] ) { size_t n = 0; while ( *dict[n] ) ++n; return n; } 你很幸运,你在表格的最后一个元素之后有某种零值。
    • @PeterJ 你错了。我不走运。我只是一个合格的失业者。:) 该数组被声明为具有 10 个元素。但是仅显式提供了 8 个初始化器。其余两个元素用零初始化。也就是说,它们包含空字符串。代码格式正确且正确。
    • @PeterJ 最初在问题中,数组有两个元素的标记值为 NULL。因此,考虑到函数是为具有标记值的数组编写的,那么用作参数的数组应该具有标记值。在我的程序中,数组也有一个哨兵值。只是它的标记值不是 NULL,而是一个空字符串。所以我不明白你在说什么“正常语言”。至于我,我说的是 C 并使用问题中显示的方法。
    • @Vlad 来自莫斯科,所以你的函数是做什么用的:char dict[10][9] = { "aap", "bro ", "jojo", "koe", "kip", "haha", "hond", " drop", "mod", "bod" }; 会不会是 UB?
    【解决方案3】:

    由于"bro"是一个字符串常量,dict[1]指向它,dict[1]指向一个字符串常量。

    当您使用strcpy(dict[1]), ... 时,您正在尝试修改dict[1] 指向的东西。但它指向一个常数。所以你正在尝试修改一个常量。

    常量不能修改。

    【讨论】:

    • C 有各种常量,但没有指定字符串常量字符串字面量 不是真正的常量,但尝试更改它们就像strcpy(dict[1]), ... 中的UB
    【解决方案4】:

    据我了解,不可能写入字符串文字。

    【讨论】:

    • 写入字符串文字并非“不可能”。尝试这样做是未定义的行为 - 它可能“工作”,它可能不会。
    • @chux 感谢您的评论;这才是我真正的意思。
    【解决方案5】:

    指针指向的内存是只读的,因为"string" 是一个字符串字面量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-09
      • 2016-03-16
      • 2023-03-31
      相关资源
      最近更新 更多