当前位置:  开发笔记 > 编程语言 > 正文

为什么我不能使用`=`复制数组?

如何解决《为什么我不能使用`=`复制数组?》经验,为你挑选了2个好方法。

我开始通过阅读K&R并完成一些练习来学习C语言.经过一番挣扎,我终于可以用以下代码完成练习1-19:

/* reverse: reverse the character string s */
void reverse(char s[], int slen)
{
  char tmp[slen];
  int i, j;

  i = 0;
  j = slen - 2;    /* skip '\0' and \n */

  tmp[i] = s[j];
  while (i <= slen) {
    ++i;
    --j;
    tmp[i] = s[j];
  }

  /* code from copy function p 29 */
  i = 0;
  while ((s[i] = tmp[i]) != '\0')
    ++i;

}

我的问题是关于tmpchar数组被复制到的最后一段代码s.为什么不是简单的s = tmp;工作呢?为什么必须按索引遍历数组复制索引?



1> Jonathan Lef..:

也许我只是老了,脾气暴躁,但我见过的其他答案似乎完全忽略了这一点.

C不执行数组赋值,句点.您不能通过简单的赋值将一个数组分配给另一个数组,这与其他语言不同(例如PL/1; Pascal及其后代的许多--Ada,Modula,Oberon等).C也没有真正的字符串类型.它只有字符数组,你不能复制字符数组(除了你可以复制任何其他类型的数组)而不使用循环或函数调用.[字符串文字实际上不算作字符串类型.]

复制数组的唯一时间是将数组嵌入到结构中并执行结构分配.

在我的K&R第2版副本中,练习1-19要求提供功能reverse(s); 在我的K&R第1版副本中,它是练习1-17而不是1-19,但同样的问题被问到了.

由于在此阶段尚未涵盖指针,因此解决方案应使用索引而不是指针.我相信这会导致:

#include 
void reverse(char s[])
{
    int i = 0;
    int j = strlen(s) - 1;
    while (i < j)
    {
        char c = s[i];
        s[i++] = s[j];
        s[j--] = c;
    }
}

#ifdef TEST
#include 
int main(void)
{
    char buffer[256];
    while (fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        int len = strlen(buffer);
        if (len == 0)
            break;
        buffer[len-1] = '\0';  /* Zap newline */
        printf("In:  <<%s>>\n", buffer);
        reverse(buffer);
        printf("Out: <<%s>>\n", buffer);
    }
    return(0);
}
#endif /* TEST */

使用-DTEST编译它以包含测试程序,而不必仅reverse()定义函数.

使用问题中给出的函数签名,您可以避免strlen()每行输入调用两次.注意使用fgets()- 即使在测试程序中,使用它也是一个坏主意gets().与之fgets()相比的缺点gets()fgets()不会删除尾随的换行符gets().好处fgets()是,你没有得到数组溢出,你可以判断程序是否找到换行符或者在遇到换行符之前是否用尽了空格(或数据).



2> Ben S..:

您的tmp数组是在堆栈上声明的,因此当您的方法完成时,用于保存值的内存将因为作用域而被释放.

s = tmp意味着s应该指向相同的内存位置tmp.这意味着当tmp释放时,s仍将指向现在可能无效的,释放的内存位置.

这种类型的错误称为悬空指针.

编辑:这不是这个答案的评论中指出的悬空修饰符.问题在于s = tmp只说改变参数指向的内容,而不是实际传递的数组.

此外,您可以通过单次传递执行反向操作,而无需在内存中分配整个数组,只需将值逐个交换:

void reverse(char s[], int slen) {
    int i = 0;        // First char
    int j = slen - 2; // Last char minus \n\0
    char tmp = 0;     // Temp for the value being swapped

    // Iterate over the array from the start until the two indexes collide.
    while(i < j) {
        tmp = s[i];  // Save the eariler char
        s[i] = s[j]; // Replace it with the later char
        s[j] = tmp;  // Place the earlier char in the later char's spot
        i++;         // Move forwards with the early char
        j--;         // Move backwards with the later char
    }
}


在他的代码中没有悬空指针,将tmp分配给s只是修改指向数组的指针的本地副本.当函数返回时,原始的s指针和数组完全不受影响.
Elitecoder,定义是**是一个数组(可变长度数组).指向数组(该数组)的指针的定义是char(*ptmp)[slen] =&tmp; 如果我们将tmp称为数组,我不明白为什么它会"让他陷入混乱",因为它*是一个数组.sizeof(tmp)会让你瘦长.什么不是数组是s.事实可能令人困惑,但这并不意味着我们应该通过告诉错误的事情使它看起来更简单 - **会让他感到困惑!请在开玩笑之前开始阅读标准
不会说tmp作为一个数组就像让他长时间处于困惑之中一样.tmp是指向数组的指针,这是正确的定义.他越早学会越好,不是吗?
推荐阅读
mylvfamily
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有