在结构C++中使用char*或char[]
Using char* or char [] in struct C++
我正在创建一个名为student
的struct
。为了存储名称,只在struct
中声明char
指针而不是预定义大小的char
数组有什么问题吗?然后,我可以在主代码中为char
指针分配一个字符串文字。
struct student
{
int ID;
char* name;
};
这实际上取决于您的用例。如上所述,您应该在C++中使用std::string
。但是,如果您使用的是C风格的字符串,那么这取决于您的使用情况。
使用定义大小的char[],可以避免由于空指针和其他与指针相关的错误(如内存泄漏、悬挂指针等)而导致的错误,但可能无法最佳利用内存。例如,您可以定义
#define MAX_SIZE 100
struct student
{
int ID;
char name[MAX_SIZE];
};
然后
#define STUDENT_COUNT 50
struct student many_students[STUDENT_COUNT];
但学生姓名的长度会有所不同,在许多情况下会比MAX_SIZE短得多。如此多的记忆将在这里被浪费。或者在某些情况下,它可能大于MAX_SIZE。您可能需要截断此处的名称以避免内存损坏。
在我们定义使用char*的其他情况下,内存不会被浪费,因为我们只分配了所需的数量,但我们必须注意内存的分配和释放。
struct student
{
int ID;
char *name;
};
然后,在存储名称时,我们需要这样做:
struct student many_student[STUDENT_COUNT];
int i;
for( i=0; i<STUDENT_COUNT; i++) {
// some code to get student name
many_student[i].name = (char*)malloc(name_length+1 * sizeof(char));
// Now we can store name
}
// Later when name is no longer required free it
free(many_student[some_valid_index_to_free].name);
// also set it to NULL, to avoid dangling pointers
many_student[some_valid_index_to_free].name = NULL;
此外,如果您再次将内存分配给name,您应该释放以前分配的内存,以避免内存泄漏。另外一件需要考虑的事情是在使用之前对指针进行NULL检查,即,您应该始终检查为
if(many_students[valid_index].name!=NULL) {
// do stuff
}
虽然您可以创建宏来完成此操作,但这些都是指针的基本开销。
使用指针的另一个优点是,如果有许多相似的名称,则可以将多个指针指向同一名称并节省内存,但在数组中,所有指针都有单独的内存,例如
// IF we have a predefined global name array
char *GLOBAL_NAMES[] = {"NAME_1", "NAME_2", "NAME_3", "NAME_4", ... , "NAME_N"};
// using pointers, just need to assign name to correct pointer in array
many_student[valid_index_1].name = GLOBAL_NAMES[INDEX_NAME_1];
many_student[valid_index_2].name = GLOBAL_NAMES[INDEX_NAME_1];
// In case of array we would have had to copy.
虽然这可能不是你的情况,但只是说指针可能有助于避免额外的使用。
希望它能帮助你:)
两者都不要使用,使用std::string
。我(和许多其他人)保证,与char*
或char[]
相比:
- 它将更易于使用并且
- 它将不太容易出现错误
差异与静态和动态内存分配之间的差异相同。对于前者(静态),您必须指定足够的大小来存储名称,而对于后者,您必须注意在不需要时删除它。
尽管使用std::string
总是更好的。
除非有充分的理由不这样做,否则我建议您使用方便的字符串类,如std::string
而不是原始char*
指针。
使用std::string
将大大简化您的代码,例如,结构将自动可复制,字符串将自动释放,等等。
不能使用std::string
的一个原因是因为您正在设计接口边界,例如Win32 API,它们主要是基于C接口的(可以在C++中实现),因此您不能在边界处使用C++,而必须使用纯C。
但如果不是这样,请帮自己一个忙,使用std::string
。
还要注意的是,如果您必须使用原始char*
指针,您有几个设计问题需要澄清,例如:
-
这是拥有指针,还是观察的指针?
-
如果它是一个拥有指针,它以什么方式分配,以什么方式释放?(例如
malloc()
/free()
、new[]
/delete[]
、一些其他分配器,如COMCoTaskMemAlloc()
、SysAllocString()
等) -
如果它是一个观察指针,则必须确保观察到的字符串的生存期超过观察指针的生存期,以避免悬挂引用。
如果使用方便的字符串类(例如std::string
),所有这些问题都不存在。
还要注意的是,正如一些Win32数据结构所做的那样,您可以在结构中有一个最大大小的字符串缓冲区,例如
struct Student
{
int ID;
char Name[60];
};
在这种情况下,您可以使用像strcpy()
这样的C函数或更安全的变体,将源字符串深度复制到Name
缓冲区中。在这种情况下,由于名称字符串位于结构内部,因此具有良好的局部性,并且相对于原始char*指针情况,简化了内存管理,但代价是具有预先分配的内存缓冲区
根据您的特定编程环境,这可能是一个更好的选择,也可能不是。无论如何,请记住,这是一种更像C的方法;更好的C++方法是只使用像CCD_ 27这样的字符串类。
TL;DR-使用std::string
,正如我们在c++
中所说的那样。
编辑:以前,根据C
标签(当前已删除)
根据您的要求,为分配字符串文字需要一个指针,无论如何,您不能用数组来实现这一点#
如果你使用该指针来存储字符串文字的基地址,那么它是可以的。否则,你需要
- 在使用该指针之前分配内存
- 用完内存后就释放内存
#)编译时分配数组的基址无法更改,因此assignment
无法工作
使用std::string库。使用它更容易。与内置的同类产品相比,它具有更多的功能。
- 具有结构成员char数组的sscanf
- 带有 char[] 字段的 POD 结构的 constexpr 构造
- 将结构 std::memcpy 转换为具有足够容量的 std::vector 是未定义的行为<char>吗?
- 成员引用基类型 'char' 不是 C++ 中的结构或联合
- C 结构具有CHAR数组以不寻常的方式初始化为零
- w/ w/结构带char缓冲液的静态初始化[]
- 是否很好地定义了强制转换为仅由 char[] 组成的结构并从该数组读取?
- 如何在结构中序列化unique_ptr<char[]>
- char*在结构内存分配中
- Realloc char* 内部结构
- C++将结构强制转换为 std::矢量<char>内存对齐
- 将包含位字段和动态数据的结构复制到 Char 数组缓冲区中
- C MPI创建并发送具有字段char [16]和整数的结构数组
- 数据结构对齐:为什么Char和STD :: String的数组不同
- 使用 JNA 访问包含 vector<char* 的结构>
- 将char*转换为C 的结构
- 使用 char* 将结构传递给 C# 中的 C++ dll 函数
- 清空包含char*的结构数组
- 如何将STD :: String的值复制到Char数组类型的结构成员
- 为什么"char"结构类型中的编程实践不好?