构造函数对 const C 字符串数组的帮助
Posted
技术标签:
【中文标题】构造函数对 const C 字符串数组的帮助【英文标题】:Constructor help with const C-string array 【发布时间】:2010-09-30 05:18:18 【问题描述】:我有一个简单的类名:
class Name
private:
char nameStr[30];
public:
Name(const char * = "");
char * getName() const;
void print() const;
;
我有两个问题,这对我来说有点困难。构造函数应该采用 const char *
的参数并将其复制到 nameStr 数组中。但是,这是我尝试过但不起作用的方法:
Name::Name(const char * setName)
&nameStr = setName;
它给了我错误“赋值中的左值无效”。如果我删除 nameStr 前面的引用,它仍然会出错,说“将 'const char*' 分配给 'char[30]' 时类型不兼容”。不太清楚我错过了什么。
另一个问题是访问器方法:
char * Name::getName() const
return &nameStr[0];
我有同样的问题,它错误“从 'const char*' 到 char*' 的无效转换”,我无法终生弄清楚如何让它返回一个指向 const char 的指针。 . 我一直在寻找有用的。在 const 上找到了大量信息,但不太清楚如何将其应用于我的情况。任何帮助将不胜感激!
【问题讨论】:
相关,你应该问问自己为什么使用 char[30] 而不是 std::string。如果没有出现重要原因,则其他问题自动解决。 我也强烈推荐使用 std::string 除非有充分的理由不这样做。处理 std::string 对象会容易得多。 嘿,感谢关于 std::string 的提示。它是作业的一部分,因此必须使用 C 风格的字符串。我应该在问题中注明。 【参考方案1】:线
char nameStr[ 30 ];
相对于(例如)
char * nameStr;
建议您要保留整个字符串的“副本”,而不仅仅是指针。所以,
&nameStr = setName;
没有意义。您可以使用类似的东西(但可能不完全一样)
strncpy( nameStr, setName, 30 );
然而,关于第二个问题,为什么要让getName()
方法返回char *
?我看到 Name
类正在封装一个 char
数组,但是如果你暴露了 char
指针,你就破坏了你自己的封装。如果您真的需要,您可以通过return nameStr;
返回一个const char *
,但最好避免这种情况。
【讨论】:
memcpy 对于这样的事情有点不安全,如果你真的想使用它,memcpy(nameStr, setName, 30*sizeof(char));会更合适。 @KSchimdt:完全同意。我只是继续并专注于这个问题,没有太大变化。实际上,我可能会使用enum N = 30 ; char nameStr[ N ];
,或者甚至使用std::string
(如果有)。 (在工作中,我没有std
:-9)
sizeof(char)
== 1 根据定义。我建议你使用 std::string,但首先你需要知道指针是如何工作的。
我们来解决你的第一个问题:&nameStr = setName;
这里,nameStr
是一个字符数组,用于存储您的姓名。 &nameStr
指的是这个数组的地址。您不能设置任何类型的变量的地址,这是非法的。例如,&a = &b
(其中 a 和 b 是整数)同样非法。接下来你尝试了nameStr = setName;
,它说来自const char* to char[30]
的转换不兼容。您要做的是将一个指针分配给另一个指针。这实际上并没有复制数据。要复制数据,您需要手动执行此操作,例如:
for (int n=0;(n>0?setName[n-1]!=0:true);n++) nameStr[n] = setName[n];
// The above won't work (or might crash) if the ternary operator evaluates both sides. I don't think it does, but correct me if I'm wrong.
请注意,与 setName[n-1]
而不是 setName[n]
的比较是为了复制 NULL 字符。
对于您的下一个问题,cannot convert const char* to char*
。获取变量的地址总是会产生一个常量指针,因为您不允许更改地址。另请注意,&array[0]
与array
基本相同,因为您先取消引用,然后重新引用它,从而使该过程变得不必要。您需要将您的 getName() 函数声明为返回 const char*
并在其中返回 nameStr
。
关于数组的一句话:数组和其他数据类型一样,只是它们包含多个数据类型,而不是一个。引用数组时,其类型是指向其成员类型的指针。例如,整数数组将被视为int*
。指针指向它的第一个元素。这意味着在数组上使用 [] 将取消引用指向其任何元素的指针。
祝 C++ 好运!
【讨论】:
太棒了,帮助很大,谢谢!我刚刚开始学习 C++,并且对指针有所了解,但还没有完全掌握。感谢您提供有关数组和被尊重的提示。 哦,我多么希望我可以使用 std::string,但这是作业的一部分,我有一些限制。虽然我认为这是接受挑战的好方法。 第一次运行循环时,您将在 setName 范围之外进行索引,这不是一个好主意...(当 n=0 变为 setName[-1] 时,setName[n-1]) “取消引用变量总是会产生一个常量指针”这不准确。他得到一个 const 指针的原因是因为他在一个类中声明了一个静态大小的数组。指针必须始终指向该类中的数据(30 个字符在该类中并影响其大小。)但话又说回来,也许您的意思是“获取地址”而不是“取消引用”。并 +1 以获得详细的答案。 是的,我做到了……小错误。我会改正错误。哦,很高兴你发现这很有帮助。【参考方案3】:当您在类或结构中声明 char nameStr[30]
之类的内容时,它会在类内的内存中创建 30 个连续字符。 nameStr
的值是指向类中该确切位置的常量指针,因此您无法更改它。你必须使用类似的东西
strncpy(nanemStr, setName, 30)
.
这会复制字符串的内容并添加一个空终止符。它限制为 30 个字符,因此您不会溢出缓冲区并破坏整个宇宙。
【讨论】:
毁灭宇宙?缓冲区溢出在最坏的情况下会导致运行时错误。 请注意,如果要复制的字符串长度至少为 30 个字符,则 strncpy 不会以空值结尾。如果 OP 使用的是 Visual Studio,他可以使用 strcpy_s,如果不是,则可以轻松地将 strcpy 与他自己的 strcpy_s 包装起来。 @Alex:超出数组范围的写入是未定义的行为,这意味着 任何事情 都可能发生(如果计算机能够以某种方式做到这一点,则包括对宇宙的破坏) . 那太糟糕了...不过我认为我的电脑做不到。 从程序的角度考虑。未处理的异常就像炸死一样。 (如果调试器得到你,它会让你陷入困境!)【参考方案4】:如果您愿意使用 std::string,您可以执行以下操作:
#include <string>
class Name
private:
std::string nameStr;
public:
Name(std::string = "");
std::string getName() const;
void print() const;
;
Name::Name(std::string setName)
nameStr = setName;
std::string Name::getName() const
return nameStr;
【讨论】:
setter 应该采用 std::string 引用,因此它不会创建不必要的副本。 谢谢,但这是作业的一部分,我们使用的是 C 风格的字符串。我多么希望我可以使用 std::string。 @ross,好的。我只是想无论如何我都会把这个建议放在那里。 @KSchmidt,说得好。【参考方案5】:为了澄清错误消息的含义,语句&nameStr = setName;
字面意思是“将nameStr 的地址设置为存储在变量setName 中的值”。你永远不能改变变量地址的值;这是在定义变量时分配的常量。因此,&nameStr
正如编译器所说,是一个无效的左值。
【讨论】:
【参考方案6】:第一个问题 -
However, this is what I have tried and is not working:
Name::Name(const char * setName)
&nameStr = setName;
It gives me the error "invalid lvalue in assignment".
因为&nameStr
给你nameStr
的地址,你不能给它赋值,所以不能在任何赋值语句中用作左值。
If I remove the reference in front of nameStr, it still errors, saying
"incompatible types in assignment of 'const char*' to 'char[30]'"
因为nameStr
是一个字符数组,而 C++ 中的数组名称是指向其第一个元素的不可变指针。这意味着您无法更改它指向的位置。
因此,也许你应该尝试这样的事情 -
strcpy(nameStr, setName);
第二个问题 -
char * Name::getName() const
return &nameStr[0];
同样的道理——&nameStr[0]
仍然等同于写简单的nameStr
。
尝试更改您的函数签名,例如 -
const char * Name::getName() const
【讨论】:
以上是关于构造函数对 const C 字符串数组的帮助的主要内容,如果未能解决你的问题,请参考以下文章
字符串类中的字符串(const char *)构造函数内存泄漏