【问题标题】:C - Returning array as function argumentC - 返回数组作为函数参数
【发布时间】:2017-01-16 00:54:01
【问题描述】:

我试图将字符数组“p”传递给函数“func”并将其复制到函数内的另一个参数“arg”。但是,该数组没有被复制,虽然我能够修改“func”中“p”的内容并能够验证主函数中的更改,但“res”不会与值一起被复制从'p'。它打印空白。我不确定我犯了什么错误。

#include <stdio.h>
#include <stdlib.h>

void func(char *c, int size, char *res)
{
        int i;
        printf("Printing c in func...\n");
        for(i=0;i<size;i++) {
                printf("%c",c[i]);
        }
        printf("\n");
        c[2] = 'j';
        res = c;
}

int main(void)
{
        char c[5]={'h','e','l','l','o'};
        char *p,*arg;
        int i, size = 5;
        p=c;
        arg = (char*)malloc(size);
        func(p,size,arg);
        printf("Printing p in main...\n");
        for(i=0;i<size;i++) {
                printf("%c",p[i]);
        }
        printf("\n");
        printf("Printing arg in main...\n");
        for(i=0;i<size;i++) {
                printf("%c",arg[i]);
        }
        printf("\n");

        return 0;
}

输出:

Printing c in func...
hello
Printing p in main...
hejlo
Printing arg in main...

【问题讨论】:

    标签: c arrays function


    【解决方案1】:

    在 C 中,函数的参数是按值传递的。函数执行结束后,位置resc 不存在。请注意,您所做的更改是指针本身而不是位置指针指向的。因此,res 的任何更改对main 都是不可见的。

    要使更改对main 可见,您需要将arg 的地址传递给函数func

    func签名应该是

    void func(char *c, int size, char **res) ;  
    

    它来自main的调用应该是

    func(p, size, &arg);  
    

    还要在函数func 中将分配res = c; 更改为*res = c;

    在这种情况下,您将传递指针arg 的地址,并对res 指向的位置进行更改。 res 指向reg 的地址,因此对res 指向的地址的任何更改都将持续存在并且对main 可见。

    现在看看它是如何工作的。最初,当您在建议的更改后调用您的函数 func 时:

          +-----------+                (0x300 is a random memory location)
          |           |
    arg   |   0x300   | <---------+
          |           |           |
          +-----------+           |
            0x100                 |
                                  |
                                  |
          +-----------+           |
          |           |           |
    res   |   0x100   +-----------+
          |           |
          +-----------+
             0x200
    

    当您将c 分配给*resreg 的别名)时,*res 将使reg 指向c 指向的位置。假设字符串hello 存储在0x500 然后*res = c 将使reg 指向0x500

                                                                Array c (in main)
          +-----------+                                  +-----+-----+-----+-----+-----+------+
          |           +--------------------------------->+ 'h' | 'e' | 'j' | 'l' | 'o' | '\0' |
    arg   |   0x500   | <---------+                      +-----+-----+-----+-----+-----+-------                                      
          |           |           |                       0x500  .... 
          +-----------+           |
            0x100                 |
                                  | *res = c
                                  |
          +-----------+           |
          |           |           |
    res   |   0x100   +-----------+
          |           |
          +-----------+
             0x200
    

    【讨论】:

    • 谢谢。那么,即使函数退出,对数组 'p' 的更改如何保留?
    • @Gomu;编辑了答案。
    【解决方案2】:

    在 C 中,指针通过值传递给函数,所以在你的函数中:

    void func(char *c, int size, char *res)
    

    res 是一个与传递给它的指针完全不同的对象

    func(p, size, arg);
    

    也就是说,它与arg 不同,但它指向(仅指向)与arg 在传递给此函数时指向的相同位置。

    因此赋值

    res = c;
    

    该函数内部的mad仅更改本地指针(函数内部的指针)。如果你这样做了

    *res = *c;
    

    那么指向的内存会被改变,并且从函数外部可以看到,因为原始指针指向的内存相同 作为res 所指的那个。这也是为什么将'j' 写入c[2] 会更改原始数组的原因:

    c[2] = 'j'; /* note: this is same as *(c + 2) = 'j'; and this is why it works - you
                   are using memory pointed to by pointer */
    

    如果您需要更改指针本身,则需要将地址传递给该指针:

    void func(char *c, int size, char **res)
    

    【讨论】:

    • 但是,即使在函数退出后,对数组“p”的更改如何保留?
    • 这是因为 c[2] = 'j' 将 'j' 写入 c + 2 指向的内存。
    猜你喜欢
    • 2023-03-14
    • 2011-08-30
    • 2011-02-21
    • 2014-06-27
    • 1970-01-01
    • 2017-11-09
    • 2018-11-27
    • 2012-06-04
    • 2012-09-26
    相关资源
    最近更新 更多