【问题标题】:why the actual parameter is altered in the first code?为什么在第一个代码中更改了实际参数?
【发布时间】:2014-01-12 17:39:55
【问题描述】:

//Herbert Schildt 的引用//

这是第一个代码

void change(char *);

int main(void)
{
    char target[80]="hello";
    change(target);
    printf("%s",target);//printing aaaaa
    return 0;
}

void change(char *tar)
{
    int i;   
    for(i=0;i<strlen(tar);i++)
    {
        tar[i]='a';
    }
}

这是第二个代码

void change(char *);

int main(void)
{
    char target[80]="hello";
    change(target);
    printf("%s",target);/printing hello
    return 0;
}

void change(char *tar)
{
    int i;
    tar="aaaaa";
}

尽管没有传递地址

target

为什么是

中的字符串
target

在第一个代码中被改变,但在第二个代码中没有

为什么要打印第一个代码

aaaaa

第二个代码打印

hello

【问题讨论】:

    标签: c pointers output


    【解决方案1】:

    第一段代码改变了tar所指向的字符的内容。第二部分将局部变量tar 本身更改为指向不同的内存位置,而不是指向原始内存的内容。因此,main() 中的原始内容在第二种情况下被保留。

    【讨论】:

    • 但是 tar 如何指向目标,因为我没有将地址作为参数传递
    • @user3180902 因为T 类型的数组在表达式中使用时会衰减为指向T 类型的指针。所以当你写change(target)时,target会衰减成一个指针。
    • 但我认为这两个代码的情况相似..我无法得到两个代码之间的区别
    • 但是第一个代码使用tar[i],所以你要取消引用tar 并写入那个特定的内存位置。第二个代码没有这样做,它只是改变了指针
    • 在您的答案中取消引用意味着什么
    【解决方案2】:

    快速回答:在这两种情况下,传递给change 函数的是指针值(不是指针对象)。该指针值是target 数组的第一个元素的地址。在第一个示例中,change 函数修改了该指针指向的数组。在第二个示例中,change 函数修改了指针。具体来说,它修改了函数的指针的本地副本,对调用者没有影响。

    //Herbert Schildt 的引用//

    这是你的第一个问题。 Herbert Schildt 写了几本关于 C 的书,但他真的不太了解这门语言。阅读由真正的 C 专家撰写的他的书的一些评论:The Annotated Annotated C Standard,由 Clive D.W. 撰写。 Feather 和 C: The Complete Nonsense,由 Peter "Seebs" Seebach 撰写。

    我不知道你的例子来自哪本书。他对int main(void)的使用是正确的,可能表明这是他后来的著作之一;在他早期的书中,他使用了void main(void),这是明显不正确的(或至少无缘无故地不可移植)。

    找一本更好的书。

    在你的第一个例子中:

    void change(char *tar);
    ...
    char target[80]="hello";
    change(target);
    

    参数tar是一个指针。那个指针没有改变; change 函数更改指针指向的内容。 target 是一个数组对象,但在 C 语言中有一条特殊规则,即在大多数情况下,数组类型的表达式会隐式转换为指向数组第一个元素的指针。 (例外情况是当数组是一元 &amp;sizeof 运算符的操作数,或者当它是用于初始化数组对象的初始化程序中的字符串文字时;这些都不适用。)

    所以在调用change(target) 时,传递给change 函数的参数是指向数组元素target[0] 的指针(等效地,地址);调用change(&amp;target[0]) 将完全等效。通过指针运算,该函数不仅可以更改指针指向的char 对象,还可以更改属于同一数组元素的其他char 对象。 ([] 索引运算符是根据指针算法定义的。)

    顺便说一下,这个循环:

    for(i=0;i<strlen(tar);i++)
    /* ... */
    

    效率极低。它在循环的每次迭代中重新计算strlen,并且每次重新计算都会遍历整个字符串。

    第二个示例中的change 函数完全不同:

    void change(char *tar)
    {
        int i;
        tar="aaaaa";
    }
    

    赋值复制的是指针值,而不是数组值。 (C 中没有数组赋值;这就是为什么我们有像strcpymemcpy 这样的函数。)tar 和第一个例子一样,是指针类型的参数。参数是一个局部变量,它从调用者传递的相应参数中获取其初始值。赋值修改了该局部变量(因此它指向与字符串字面量关联的数组),但它对调用者传入的值没有影响。

    最后,在这两个例子中,主程序都是这样做的:

    printf("%s",target);
    

    (顺便说一句,它应该是"%s\n",而不仅仅是'%s"。)计算表达式target的结果没有改变;它是数组的基地址,只要数组存在,它就是固定的。那么为什么输出会改变呢?因为%s 格式说明符与任何其他printf 格式说明符不同,打印的不是相应参数的值,而是它所指向的值。

    建议阅读:comp.lang.c FAQ 的第 6 节,标题为“数组和指针”。这是我所知道的用于解释 C 中数组和指针之间经常令人困惑的关系的最佳资源。

    【讨论】:

    • 如果我在第二个代码中编辑更改如下 strcpy(tar,"aaaaa");那么它正在打印 aaaaa not hello 为什么?
    • @user3180902:因为strcpy修改了数组tar指向。
    • 和 tar="aaaaa" 不是修改?
    【解决方案3】:
    char *string  = "something between quotes" 
    

    当您在 C 中使用双引号并在其中放入一个字符串时,C 会自动为我们创建一个数组并将双引号之间的内容放入该新数组,并且指向该新数组的指针现在放在 字符串变量。在您的情况下,“aaaa”将在内存中的某处(可能在数据部分)创建一个新数组,然后将指向这个新数组的指针提供给 tar,表达式从右到左进行评估,因此首先评估“aaaa”并然后将其结果提供给 tar。所以在初始化数组时基本上总是使用双引号“sometinh here”。

    @Filipe Goncalves 的答案是正确的答案,我无法在评论中写这个,所以不得不发一个新帖子。

    【讨论】:

    • 对不起@Filipe Goncalves 我的意思是说 OP 很困惑,你的答案是正确的.. 我的错误让名字混淆了..
    • 如果我将第一个代码中的函数更改编辑为 *tar[i]='a';
    • 你不需要 *,tar[i] = 'a' 会打印 aello,*tar[i] 会给你一个错误,我假设 i 是 0。tar[0] = ' a' 这将打印 aello。
    • 从右到左计算表达式 这不是真的。根据表达式,评估顺序可能是未定义的 - 说这个时要小心
    • 这几乎是一个很好的答案,但它有两个主要缺陷。 “指向该新数组的指针现在被放入string 变量中”——不,没有指针对象。 string 是一个数组,而不是一个指针。 "表达式从右到左求值" -- 不,在大多数情况下,求值顺序是未指定的;在定义评估顺序的少数情况下,它是从左到右的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多