【问题标题】:Pass char pointer/array to a function将 char 指针/数组传递给函数
【发布时间】:2014-07-22 14:33:11
【问题描述】:

我试图更多地理解 C 中的 char 指针,但有一件事让我明白了。

假设我想将一个 char 指针传递给一个函数并更改指针所代表的值。示例如下:

int Foo (char *(&Msg1), char* Msg2, char* Msg3){
    char *MsgT = (char*)malloc(sizeof(char)*60);
    strcpy(MsgT,"Foo - TEST");
    Msg1 = MsgT; // Copy address to pointer
    strcpy(Msg2,MsgT); // Copy string to char array
    strcpy(Msg3,MsgT); // Copy string to char pointer
    return 0;
}

int main() {
    char* Msg1; // Initial char pointer
    char Msg2[10]; // Initial char array
    char* Msg3 = (char*)malloc(sizeof(char) * 10); // Preallocate pointer memory
    Foo(Msg1, Msg2, Msg3);
    printf("Msg1: %s\n",Msg1); // Method 1
    printf("Msg2: %s\n",Msg2); // Method 2
    printf("Msg3: %s\n",Msg3); // Method 3
    free(Msg1);    
    free(Msg3);
    return 0;
}

在上面的例子中,我列出了所有我知道的将 char 指针传递给函数的工作方法。我不明白的是方法1

char *(&Msg1)对于传递给函数Foo的第一个参数是什么意思?

此外,method 2method3 似乎被书籍和教程广泛介绍,其中一些甚至将这些方法称为最正确的方法传递数组/指针。我想知道 方法 1 对我来说看起来很不错,尤其是当我编写我的 API 时,用户可以轻松地将空指针传递给函数,而无需预先分配内存。如果用户忘记释放内存块,唯一的缺点可能是潜在的内存泄漏(与 方法 3 相同)。有什么理由我们应该更喜欢使用 方法 2 或 3 而不是 方法 3

【问题讨论】:

  • 你在什么地方看到过这个例子吗?常用char **Msg1代替char *(&Msg1)
  • 不幸的是,这是我很久以前记的笔记。我什至不记得我从哪里得到这个。我了解**Msg1 的工作原理,但它们是不同的,对吧?
  • char *(&Msg1) 是 C++ 引用传递。
  • 同时学习 C 和 C++ 不是一个好主意! 它们非常相似,以至于您可能认为它们非常不同的地方并不重要。
  • @StevenChang 它不能用 ac 编译器编译,但用 C++ 编译器编译得很好,在 C 中它被认为是语法错误,而在 C++ 中,它被认为是reference,如果你不这样做了解参考文献,您应该阅读更多关于它们的信息

标签: c++ c pointers char char-pointer


【解决方案1】:

int f(char* p) 是 C 中将指针 p 传递给函数 f 的常用方法,此时 p 已经指向您需要的内存位置(通常是因为那里已经分配了一个字符数组作为在您的方法 2 或方法 3 中)。

int f(char** p) 是 C 中将指针 p 传递给函数 f 的常用方法,当您希望 f 能够为该函数的调用者修改指针 p 时。您的方法 1 就是一个例子;您希望f 分配新内存并使用p 告诉调用者该内存在哪里。

int f(char*& p) 是 C++,而不是 C。由于它会为您编译,因此我们知道您使用的是 C++ 编译器。

【讨论】:

  • 现在我明白了,不同编译器的语法不同。但是如果使用f(char** p),则需要在初始化指针后传递&Msg,对吧?它看起来不像 Method 1。如果使用 C++ 编码,首选哪种方式?为什么?
  • 您是正确的,您需要将&Msg 传递给f(char** p),因为Msg 的类型是char*。在 C++ 中,我更喜欢f(char*& p),部分原因是您可以只传递Msg,还因为& 是一种清楚地表明您想要传递引用语义的方法,而char** 可能只是一个另一个上下文中的字符串数组。
  • 谢谢。我认为您的解释简洁明了。这正是我需要的。
  • @StevenChang " 适用于不同的编译器" -- 不,适用于不同的语言。 “如果用 C++ 编码,首选哪种方式,为什么?” -- 参考文献优先。原因见stackoverflow.com/questions/10781661/…
【解决方案2】:

考虑当您采用int& 类型的参数时会发生什么(引用 int):

void f(int &x) {
    x++;
}

void g(int x) {
    x++;
}

int main() {
    int i = 5;
    f(i);
    assert(i == 6);
    g(i);
    assert(i == 6);
}

同样的行为可以通过一个指向 int 的指针 (int *x) 来实现,并通过 (*x)++ 对其进行修改。这样做的唯一区别是调用者必须调用 f(&i),并且调用者可以将无效指针传递给 f。因此,引用通常更安全,应尽可能首选。

采用char*(指向字符的指针)类型的参数意味着调用者和函数都“通过”该指针看到相同的内存块。如果函数修改了char*指向的内存,它会持久化给调用者:

void f(char* p) {
    (*p) = 'p';
    p = NULL; //no efect outside the function
}

int main() {
    char *s = new char[4];
    strcpy(s, "die");
    char *address = s; //the address which s points to
    f(s);
    assert(strcmp(s, "pie") == 0);
    assert(s == address); //the 'value' of the variable s, meaning the actual addres that is pointed to by it, has not changed
}

采用char*& (reference-to-(pointer-to-char)) 类型的参数与采用 int& 非常相似: 如果函数修改了指针指向的内存,调用者将照常看到它。但是,如果函数修改了指针(它的地址)的,调用者也会看到它。

void f(char* &p) {
    (*p) = 'p';
    p = NULL;
}

int main() {
    char *s = new char[4];
    strcpy(s, "die");
    char *address = s; //the address which s points to
    f(s);
    assert(strcmp(address, "pie") == 0); //the block that s initially pointed to was modified
    assert(s == NULL); //the 'value' of the variable s, meaning the actual addres that is pointed to by it, was changed to NULL by the function
}

同样,您可以使用char**(指向字符的指针),并修改f 以使用**p = 'p'; *p = NULL,调用者必须调用f(&s),具有相同的含义。

请注意,您不能通过引用传递数组,即如果将 s 定义为 char s[4],则第二个示例中的调用 f(s) 会产生编译器错误。

还要注意,这只适用于 C++,因为 C 没有引用,只有指针。

当您的函数需要返回指向它分配的内存块的指针时,您通常会使用char**char*&。您会更频繁地看到char**,因为这种做法在 C++ 中比在不存在引用的 C 中少见。

至于使用引用还是指针,这是一个备受争议的话题,如果你在谷歌上搜索“c++ 指针与引用参数”就会注意到。

【讨论】:

    猜你喜欢
    • 2016-03-27
    • 2021-09-07
    • 1970-01-01
    • 2021-12-02
    • 2012-07-28
    • 1970-01-01
    • 1970-01-01
    • 2011-05-22
    相关资源
    最近更新 更多