C++ sizeof C 风格的字符串/字符数组——优化
C++ sizeof C-style string / char array - optimization
我是一名大学生。我主要使用 Java,C++ 对我来说很新,所以我可能会犯很多愚蠢的错误,而且我还有即将到来的考试要应付。别对我太苛刻了。
注意:我不能使用 C++ std::string 因为我因为大学任务需要使用 C 字符串!
参考我的研究和我问的关于指针和 const
参数的问题(你会发现 )我试着搞乱内存管理但它似乎没有效果,或者我只是误解了某些方面 sizeof
或某些元素的实际大小。
这是我的 class 人:
Person.cpp
using namespace std;
Person::Person()
{
Person::name = new (char[64]);
Person::adress = new (char[64]);
Person::phone = new (char[64]);
cout << "standard constructor called; object created, allocated " << sizeof(name) << "+" << sizeof(adress) << "+" << sizeof(phone) << "bytes" << endl;
}
Person::Person(const char *name, const char *adress , const char *phone)
{
Person::name = new (char[strlen(name)]);
Person::adress = new (char[strlen(adress)]);
Person::phone = new (char[strlen(phone)]);
setName(name);
setAdress(adress);
setPhone(phone);
cout << "general constructor called; object created, allocated " << sizeof(this->name) << "+" << sizeof(this->adress) << "+" << sizeof(this->phone) << "bytes" << endl;
};
Person::Person(Person const &other)
{
Person::name = new (char[strlen(other.getName())]);
Person::adress = new (char[strlen(other.getAdress())]);
Person::phone = new (char[strlen(other.getPhone())]);
setName(other.getName());
setAdress(other.getAdress());
setPhone(other.getPhone());
cout << "copy constructor called; object created, allocated " << sizeof(name) << "+" << sizeof(adress) << "+" << sizeof(phone) << "bytes" << endl;
};
Person::~Person()
{
delete [] name;
delete [] adress;
delete [] phone;
cout << "destructor called; object removed" << endl;
};
我试图通过创建一个字符串长度为给定参数的 C 字符串来节省内存。
认为 C 字符串是一个字符数组,节省字符会导致节省内存,例如"John" 的 C 字符串比 "Jonathan" 的 C 字符串占用更少的内存。
所以现在我不确定是我对 C 字符串或字符数组的概念有误,还是我的实现有问题。
在我的 main 中,我创建了以下对象:
int main()
{
Person t;
t.printPerson();
cout << "size of t: " << sizeof(t) << endl;
Person p("John", "some street", "0736182");
p.printPerson();
cout << "size of p: " << sizeof(p) << endl;
Person x(p);
x.printPerson();
cout << "size of x: " << sizeof(x) << endl;
Person y("Jonathan", "Lancaster Ave 53", "3584695364");
y.printPerson();
cout << "size of y: " << sizeof(y) << endl;
cin.get();
};
但是我总是得到每个对象 24 个大小,所以每个成员变量 8 个。这是为什么?
提前致谢。
我认为您期望 sizeof
运算符的行为与实际行为不同。让我们以这段代码为例:
const char* str = new char[137];
在这里,如果你写 sizeof(str)
你可能会得到 4 或 8,这取决于你的系统,因为 sizeof(str)
测量指针 str
本身的字节数而不是 str
指向的数组中的字节数。因此,在 32 位系统上,您可能会得到 4 个,而在 64 位系统上,您可能会得到 8 个,这与您分配的字符数无关。
不幸的是,C++ 没有办法让您获得字符数或动态分配的数组所用的内存。您只需要自己跟踪即可。
类似地,在您的主函数中,当您编写 sizeof(p)
时,您正在测量对象 p
使用的字节数,而不是 [=17] 使用的总字节数=] 和它指向的数组。 sizeof(p)
无论它指向什么字符串,你总是会得到相同的值。
如果您打算在 C++ 中使用字符串,我强烈建议您使用 std::string
而不是原始 C 风格的字符串。它们更容易使用,它们会记住它们的长度(因此更难混淆 strlen
和 sizeof
),并且如果你有一个 class 持有 s 一堆 std::string
s 您不需要复制构造函数或赋值运算符来处理将它们随机播放的逻辑。这将显着清理您的代码并消除其中的大部分内存错误。
sizeof
为您提供 c/c++ 将对象保存在内存中所需的字节数。在你的情况下(虽然你没有显示它)看起来 name
、address
和 phone
是指向 char:
的指针
struct Person {
char *name, *address, *phone;
}
a pointer 是一个保存另一个对象地址的变量。因此,根据底层系统,它可能占用 32 位(4 字节)或 64 位(8 字节)(或其他数字)。在这种情况下,sizeof struct person 将用于 64 位系统 -- 24。(每 8 个字节有 3 个指针)。这对应于您的结果。
sizeof
为您提供浅尺寸计算。您的字符串由那些指针指向,并且不包括它们的长度。因此,您可能需要创建一个成员函数来为您计算这些值,即
struct Person {
char *name, *address, *phone;
int getSize() {
return strlen(name) + strlen(address) + strlen(phone);
}
};
并且如之前评论中所述,c/c++ 中的每个 char *string
都必须有一个终止字符 ('\0'),它告诉程序字符串结束的位置。所以,如果你为一个字符串分配 space,你也应该为它提供 space(长度 + 1)。而且你必须确保这个字符写成'\0'。如果你使用库函数来复制字符串,它们会自动处理,否则你需要手动完成。
void setName(const char *n) {
name = new char[strlen(n) + 1]; // includes needed '0', if exists in 'n'
strcpy(name, n); // copies the string and adds `[=12=]` to the end
}
如果您使用循环而不是 strcpy
来复制字符,则需要手动添加:
name[strlen(n)] = 0;
我是一名大学生。我主要使用 Java,C++ 对我来说很新,所以我可能会犯很多愚蠢的错误,而且我还有即将到来的考试要应付。别对我太苛刻了。
注意:我不能使用 C++ std::string 因为我因为大学任务需要使用 C 字符串!
参考我的研究和我问的关于指针和 const
参数的问题(你会发现 sizeof
或某些元素的实际大小。
这是我的 class 人:
Person.cpp
using namespace std;
Person::Person()
{
Person::name = new (char[64]);
Person::adress = new (char[64]);
Person::phone = new (char[64]);
cout << "standard constructor called; object created, allocated " << sizeof(name) << "+" << sizeof(adress) << "+" << sizeof(phone) << "bytes" << endl;
}
Person::Person(const char *name, const char *adress , const char *phone)
{
Person::name = new (char[strlen(name)]);
Person::adress = new (char[strlen(adress)]);
Person::phone = new (char[strlen(phone)]);
setName(name);
setAdress(adress);
setPhone(phone);
cout << "general constructor called; object created, allocated " << sizeof(this->name) << "+" << sizeof(this->adress) << "+" << sizeof(this->phone) << "bytes" << endl;
};
Person::Person(Person const &other)
{
Person::name = new (char[strlen(other.getName())]);
Person::adress = new (char[strlen(other.getAdress())]);
Person::phone = new (char[strlen(other.getPhone())]);
setName(other.getName());
setAdress(other.getAdress());
setPhone(other.getPhone());
cout << "copy constructor called; object created, allocated " << sizeof(name) << "+" << sizeof(adress) << "+" << sizeof(phone) << "bytes" << endl;
};
Person::~Person()
{
delete [] name;
delete [] adress;
delete [] phone;
cout << "destructor called; object removed" << endl;
};
我试图通过创建一个字符串长度为给定参数的 C 字符串来节省内存。 认为 C 字符串是一个字符数组,节省字符会导致节省内存,例如"John" 的 C 字符串比 "Jonathan" 的 C 字符串占用更少的内存。
所以现在我不确定是我对 C 字符串或字符数组的概念有误,还是我的实现有问题。
在我的 main 中,我创建了以下对象:
int main()
{
Person t;
t.printPerson();
cout << "size of t: " << sizeof(t) << endl;
Person p("John", "some street", "0736182");
p.printPerson();
cout << "size of p: " << sizeof(p) << endl;
Person x(p);
x.printPerson();
cout << "size of x: " << sizeof(x) << endl;
Person y("Jonathan", "Lancaster Ave 53", "3584695364");
y.printPerson();
cout << "size of y: " << sizeof(y) << endl;
cin.get();
};
但是我总是得到每个对象 24 个大小,所以每个成员变量 8 个。这是为什么?
提前致谢。
我认为您期望 sizeof
运算符的行为与实际行为不同。让我们以这段代码为例:
const char* str = new char[137];
在这里,如果你写 sizeof(str)
你可能会得到 4 或 8,这取决于你的系统,因为 sizeof(str)
测量指针 str
本身的字节数而不是 str
指向的数组中的字节数。因此,在 32 位系统上,您可能会得到 4 个,而在 64 位系统上,您可能会得到 8 个,这与您分配的字符数无关。
不幸的是,C++ 没有办法让您获得字符数或动态分配的数组所用的内存。您只需要自己跟踪即可。
类似地,在您的主函数中,当您编写 sizeof(p)
时,您正在测量对象 p
使用的字节数,而不是 [=17] 使用的总字节数=] 和它指向的数组。 sizeof(p)
无论它指向什么字符串,你总是会得到相同的值。
如果您打算在 C++ 中使用字符串,我强烈建议您使用 std::string
而不是原始 C 风格的字符串。它们更容易使用,它们会记住它们的长度(因此更难混淆 strlen
和 sizeof
),并且如果你有一个 class 持有 s 一堆 std::string
s 您不需要复制构造函数或赋值运算符来处理将它们随机播放的逻辑。这将显着清理您的代码并消除其中的大部分内存错误。
sizeof
为您提供 c/c++ 将对象保存在内存中所需的字节数。在你的情况下(虽然你没有显示它)看起来 name
、address
和 phone
是指向 char:
struct Person {
char *name, *address, *phone;
}
a pointer 是一个保存另一个对象地址的变量。因此,根据底层系统,它可能占用 32 位(4 字节)或 64 位(8 字节)(或其他数字)。在这种情况下,sizeof struct person 将用于 64 位系统 -- 24。(每 8 个字节有 3 个指针)。这对应于您的结果。
sizeof
为您提供浅尺寸计算。您的字符串由那些指针指向,并且不包括它们的长度。因此,您可能需要创建一个成员函数来为您计算这些值,即
struct Person {
char *name, *address, *phone;
int getSize() {
return strlen(name) + strlen(address) + strlen(phone);
}
};
并且如之前评论中所述,c/c++ 中的每个 char *string
都必须有一个终止字符 ('\0'),它告诉程序字符串结束的位置。所以,如果你为一个字符串分配 space,你也应该为它提供 space(长度 + 1)。而且你必须确保这个字符写成'\0'。如果你使用库函数来复制字符串,它们会自动处理,否则你需要手动完成。
void setName(const char *n) {
name = new char[strlen(n) + 1]; // includes needed '0', if exists in 'n'
strcpy(name, n); // copies the string and adds `[=12=]` to the end
}
如果您使用循环而不是 strcpy
来复制字符,则需要手动添加:
name[strlen(n)] = 0;