在结构C++中使用char*或char[]

Using char* or char [] in struct C++

本文关键字:char 结构 C++      更新时间:2023-10-16

我正在创建一个名为studentstruct。为了存储名称,只在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[]相比:

  1. 它将更易于使用并且
  2. 它将不太容易出现错误

差异与静态和动态内存分配之间的差异相同。对于前者(静态),您必须指定足够的大小来存储名称,而对于后者,您必须注意在不需要时删除它。

尽管使用std::string总是更好的。

除非有充分的理由不这样做,否则我建议您使用方便的字符串类,如std::string而不是原始char*指针。

使用std::string将大大简化您的代码,例如,结构将自动可复制,字符串将自动释放,等等。

不能使用std::string的一个原因是因为您正在设计接口边界,例如Win32 API,它们主要是基于C接口的(可以在C++中实现),因此您不能在边界处使用C++,而必须使用纯C。
但如果不是这样,请帮自己一个忙,使用std::string

还要注意的是,如果您必须使用原始char*指针,您有几个设计问题需要澄清,例如:

  1. 这是拥有指针,还是观察的指针?

  2. 如果它是一个拥有指针,它以什么方式分配,以什么方式释放?(例如malloc()/free()new[]/delete[]、一些其他分配器,如COMCoTaskMemAlloc()SysAllocString()等)

  3. 如果它是一个观察指针,则必须确保观察到的字符串的生存期超过观察指针的生存期,以避免悬挂引用。

如果使用方便的字符串类(例如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库。使用它更容易。与内置的同类产品相比,它具有更多的功能。