C++中的const char*和char*有何区别?

15
对于下面的程序:
int DivZero(int, int, int);

int main()
{
    try {
        cout << DivZero(1,0,2) << endl;
    }
    catch(char* e)
    {
        cout << "Exception is thrown!" << endl;
        cout << e << endl;
        return 1;
    }
    return 0;
}

int DivZero(int a, int b, int c)
{
    if( a <= 0 || b <= 0 || c <= 0)
        throw "All parameters must be greater than 0.";
    return b/c + a;
}

使用char* e会导致

抛出实例为'char const *'的异常后终止

根据C++异常处理,解决方案是使用const char*

进一步阅读函数(const char*) vs. 函数(char*)指出:

"String"的类型是char*',而不是const char*'

(我觉得这是一次C讨论...)

Stack Overflow上的附加阅读char*和const char*作为参数告诉我它们的区别。但是它们都没有回答我的问题:

  1. 似乎char*string*都有字符数限制。我对吗?
  2. 将关键字const添加到char*中如何消除该限制?我认为const的唯一目的是设置一个标志,表示“不可修改”。我理解const char* e的含义是“指向不可修改char类型的指针”。

解决该错误的方法是使用const char* e

即使是const string* e也不起作用。(仅为测试而言...)
有人能解释一下吗?谢谢!
顺便说一句,我在Ubuntu上,用GCC编译,在Eclipse上工作。
2个回答

23

关于“String”的电子邮件链接是错误的(且令人困惑)。

基本上:

char* 是指向字符数组的无界指针。传统上,如果该数组包含一组有效字符,后面跟着一个\0,我们认为这样的数组是C字符串。这个数组的大小没有限制。

const char* 是指向不可变字符数组的指针。

string* 是指向std::string对象的指针,是完全不同的东西。这是一个智能对象,封装了字符串。使用std::string而不是C字符串可以让你的生活轻松很多,尽管它们有一些棘手的细节和许多令人讨厌的陷阱;它们值得研究,但与问题无关。

"String"是一个特殊表达式,返回一个指向特定C字符串的const char*(注意:实际并非如此,但这是一个简化,让我能够简洁回答问题)。

char* 可以自动转换为 const char*,但反之不行。请注意,旧的C++编译器有一个特殊的例外,可以让你这样做:

char* s = "String";

在C++中,你可以这样做而不会产生类型错误;这是为了与C兼容。现代的C++编译器不会让你这样做(例如最近的gcc)。它们需要这样:

const char* s = "String";

所以,这里的问题是你有:

throw "All parameters must be greater than 0.";

...但是你试图使用以下方式捕获它:

catch(char* e)

这并不起作用,因为throw抛出的是一个const char*,无法转换为catch中指定的类型,所以它没有被捕获。

这就是为什么将catch改为以下形式:

catch (const char* e)

...使它工作。


4
+1,但我知道的所有编译器(包括最近的GCC)都允许您执行char* s =“String”;而不会出错。另一方面,有些编译器可能会给出警告...(演示 - ildjarn
讲得很清楚。我希望我能给每个人打分,但我不能。他比你先回答了。我猜那没关系。你的解释非常有帮助。我真的很喜欢它。谢谢,David。我实际上在"const-correctness"维基文章中找到了更多信息.... :] - CppLearner
@ildjarn,感谢您的精彩评论和演示。:] - CppLearner
@JohnWong 很高兴能帮到你(甜蜜的声望点数也很不错,嘿嘿嘿)。学习const正确性非常值得;C++是一门非常挑剔和极其微妙的语言,有时候弄对const正确性可能会很痛苦,但在以后避免出现问题时将会非常有帮助。C++不是我最喜欢的语言... - David Given

18

你为什么要抛出和捕获字符串呢?

你应该抛出和捕获异常,例如 std::runtime_error

回答你的问题是,每当你在代码中插入带引号的字符串时,它会返回一个以 null 结尾的 const char*

你的代码之所以不像上面那样工作,是因为类型不对,所以 catch 没有捕获到你抛出的内容。你抛出了一个 const char*。

char 数组中的字符数量没有限制,仅受栈/堆大小的限制。如果你指的是你发布的示例,那个人创建了一个固定大小数组,所以他们受到了限制。


@Salgar 这是《数据结构基础(第二版)》中的示例代码。如果我插入 int [],它会以 const int* 的形式返回吗?(带有 const 关键字) - CppLearner
2
同意,从std::exception派生所有异常。抛出基本类型会导致麻烦。确保所有内容都派生自std::exception可以让您确信catch(std::exception e)将捕获所有内容。您要为最极端的情况(如DLL边界)保留catch(...)。经常抛出基本类型通常会导致需要经常使用catch(...)。使用 throw std::runtime_error("所有参数必须大于0。"); - totowtwo
是的,使用“yes”可以确保catch(const std::exception& e)可以捕获所有异常。 - Salgar
1
@JongWong 不是的,"foo" 代码的类型是 const char,int[] 的类型是 int[],int 的类型是 int*。 - Salgar
2
我非常确定字符串字面值的类型是const char[N],其中N是字符串长度+(对于'\0'),而不是const char*`,它只是衰减到那个类型。 - KillianDS

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