C++字符指针传递给函数并删除

4

我有以下代码:

#include <iostream>
using namespace std;

void func(char * aString)
{
    char * tmpStr= new char[100];
    cin.getline(tmpStr,100);
    delete [] aString;
    aString = tmpStr;
}

int main()
{
    char * str= new char[100];
    cin.getline(str,100);
    cout<< str <<endl;
    func(str);
    cout<< str <<endl;
    return 0;
}

为什么第二个cout没有输出第二个输入字符串?我该如何修改这段代码使其正常工作?

1
请使用 std::stringstd::getline() 替代。 - sbi
11个回答

12
正如GregS所说,简单的答案是使用引用声明您的函数:
void func(char *&aString)

然而这并不是最好的解决方案。在 C++ 中,通常避免使用简单数组,而使用容器。

#include <iostream>
#include <string>

void func(std::string &s)
{
    std::getline(std::cin, s);
}

int main()
{
    std::string str;
    func(str);
    std::cout << str << std::endl;
    return 0;
}

在C++中没有理由使用char*或char[],因为这就是std::string的作用。 - Puppy
这是我见过的一个常见错误。如果流的getline方法一开始就接受一个字符串就好了! - Owen S.
@Owen S - 设计上,流不依赖于字符串。从设计角度来看,这有其优点。然而,对于初学者来说,这确实会使教学变得有些困难。生活就是如此 :-) - Michael J
如果你问我,这是标准C++库中最令人沮丧的事情。给我展示另一种面向对象的语言,看看它们的I/O库是否像这样将字符串对象保持在一定距离之外!呸。 :-) - Owen S.

6
因为第二个cout将打印str指向的内容。在调用func之前和之后,你的主函数中的指针变量str将具有相同的值。
事实上,在func函数中,你正在更改aString变量的值。但这是与主函数中的str不同的另一个变量。
如果你想要更改str的值,你必须通过引用或指针将其传递给func。(请注意,你写的是通过指针传递字符。我的意思是你必须通过指针传递指针:void func(char **str_ptr),或通过引用void func(char *&str_ref)如果你真的在使用C ++,应该使用std :: string而不是旧的C字符串。 传递指针的示例:
func(char ** aString)
{
    char * tmpStr= new char[100];
    cin.getline(tmpStr,100);
    delete [] *aString;
    *aString = tmpStr;
}

另外,你应该这样调用它:func(&str);


如果我这样传递参数:void func(char **str_ptr),那么我应该如何实现“func”呢? - Narek
@Didier Trosset 这里 tempStr 没有被释放。所以这是一个泄漏。如何处理? - Undefined Behaviour
1
@vidhugangwar 这是否是一个泄漏取决于func函数的文档。在这里,由于指针的值被返回给调用者,因此可能是调用者的责任来释放内存。 - Didier Trosset
@DidierTrosset,那么用户如何知道开发人员分配了100个内存呢?我认为用户将根据aString的大小来删除内存。我是对的吗?提前感谢 :) - Undefined Behaviour
1
@vidhugangwar 用户无法通过查看函数参数来知道这一点。必须在函数的文档中明确说明。 - Didier Trosset

2

将func更改为

void func(char * aString)
{
    cin.getline(aString,100);
}

它能够运作,至少对我来说是这样的。


+1 所有的引用/指针内容都不重要。如果你只是将getline的结果复制回原始缓冲区,那么没有必要创建一个单独的缓冲区来分配这些结果。只需将第一个缓冲区传递给getline即可。实际上,你真的不需要一个单独的函数来调用getline。 - John M Gant
(当然,就像其他人指出的那样)尽管您应该使用std :: string。 - John M Gant

2

当从主函数main()调用func()时,将str指针的值传递给该函数(这是通过将其值复制到堆栈中完成的)

在调用func()时存储在堆栈上的值成为func()内的本地变量aString。您可以修改此值,但是一旦func()返回,它的所有本地变量都将被丢弃。aString的值不会被复制回str

为使代码正常工作,您需要:

  • 使用由aString指向的缓冲区读取数据: cin.getline(aString, 100); 或者
  • 传递指向指针的指针:void func(char **aString)

2
请注意,如果您更改为func(char *aPtrToString),则需要在main函数中调用func(&str),然后在func函数中使用getLine(aPtrToString)。 - maxwellb

1
如果你的目的是从键盘上实际读取一行内容,可以这样做:
std::string foo;

std::getline(std::cin, foo);

否则,当您将指针传递给函数时,指针是按值传递的。这意味着您无法从函数内部更改指针本身,但可以更改它所指向的对象。在C++中,您可以按以下方式执行此操作:
void bar(std::string & s) {
    std::getline(std::cin, s);
}

// in calling code
    std::string foo;

    bar(foo);

这将字符串的引用传递给函数。函数现在可以更改字符串的内容。

如果您想编写一个分配一些内存来存储结果的函数,请按照以下方式进行:

boost::shared_array<char> foo() {
    boost::shared_array<char> result(new char[100]);
    std::cin.getline(result.get(), 100);
    return result;
}

std::cin >> foo; 不会读取整行,它会在第一个空格处停止。如果你想要整行输入,应该使用 std::getline(std::cin,foo); - Mike Seymour
另外,应该使用 shared_array 而不是 shared_ptr 来获取正确的删除器。 - Mike Seymour
再次修正 - 最近做了太多Python。 - Björn Pollex

1
指针是按值传递的。是的,您可以更改指针所指向的内容,但是当您退出函数时,旧地址本身将被保留。因此,“aString = tmpStr”变得无用,“char * tmpStr = new char [100];”会创建内存泄漏。您需要通过引用传递指针:
void func(char*& aString)
{
    char * tmpStr= new char[100];
    cin.getline(tmpStr,100);
    delete [] aString;
    aString = tmpStr;
}

0

函数内对参数aString的赋值对main()中的str没有影响。

你可以尝试:

    return aString 

并且在主函数中

    str = funct(str);

但实际上,可能没有必要将字符串传递到函数中。


0

这行代码 aString = tmpStr 只是改变了astring的值(即地址/指针)为另一个值(即另一个地址/指针),但并没有改变由aString指向的内存内容。

你可以尝试更改签名为:

void func(char ** aString)

func的最后两行更改为:

delete [] *aString;
*aString = tmpStr;

因此,最后一行代码会导致程序将指向aString的内存中存储的地址更改为新分配的地址(tmpStr)。(我知道,这很令人费解。)

然后通过调用它来执行。

func(&str);

你的意思是aString是str的一个副本吗? - Narek
他的意思是你函数中的指针'aString'是主函数'main'中指针'str'的一个副本。'char *'不是字符串,但它可以指向一个字符串。 - Björn Pollex

0
#include <iostream>

void func(std::istream& is, std::string& aString)
{
    std::getline(is, aString);
}

int main()
{
    std::string str;
    std::getline(std::cin, str);
    if(std::cin)
        std::cout<< str << '\n';
    std::string str;
    func(std::cin, str);
    if(std::cin)
        std::cout<< str << '\n';
    return 0;
}

0

你需要将 str 作为引用传递。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接