【问题标题】:Using char* or char [] in struct C++在结构 C++ 中使用 char* 或 char []
【发布时间】:2015-06-29 20:17:55
【问题描述】:

我正在创建一个名为studentstruct。为了存储名称,仅在 struct 中声明 char 指针而不是具有预定义大小的 char 数组有什么问题吗?然后我可以将字符串文字分配给主代码中的char 指针。

struct student
{
    int ID;
    char* name;
};

【问题讨论】:

  • 使用std::string
  • 使指针指向字符串字面量的问题在于,您无法修改字符串,但由于您只有char* 而不是const char*,并且如果您动态为它分配内存,那么内存泄漏就不难了。固定大小的数组的问题是,如果你想要一个更大的字符串,你就不能扩大它,如果你有一个非常小的字符串,你就会浪费很多空间。在 C++ 中,正确的解决方案是 std::string,在 C 中,解决方案取决于您的用例。
  • 我无法修改 name 指向的内容,但我不能在任何时候将 name 指向一个新的字符串文字吗?

标签: c++ string struct


【解决方案1】:

这真的取决于您的用例。如上所述,您应该在 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.

虽然这可能不是你的情况,但只是说指针可能有助于避免额外的使用。

希望对你有帮助:)

【讨论】:

  • 太棒了。谢谢你
  • 这是一个非常有用的答案。加一。我同意,取决于使用情况。如果您的输入很大(即数百万行超过 20 个字符的文本),使用 std::string 会将数百万个分配放在堆上,然后您必须非常小心,不要复制它们任何地方。在这种情况下,可能值得考虑使用 char[] 或至少只使用一次 std::string 然后在代码中使用 std:string_view 。
【解决方案2】:

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

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

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

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

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

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

  3. 如果是观察指针,则必须确保观察字符串的生命周期超过观察指针的生命周期,以避免悬空引用。

如果您使用方便的字符串类(例如std::string),那么所有这些问题都不存在。

另请注意,与某些 Win32 数据结构一样,您可以在结构中拥有一个最大大小的字符串缓冲区,例如

struct Student
{
    int ID;
    char Name[60];
};

在这种情况下,您可以使用像 strcpy() 这样的 C 函数或更安全的变体,将源字符串深度复制到 Name 缓冲区中。在这种情况下,您具有良好的局部性,因为名称字符串位于结构内部,并且相对于原始 char* 指针情况进行了简化的内存管理,但代价是具有预分配的内存缓冲区。
这对您来说可能是也可能不是更好的选择,具体取决于您的特定编程环境。无论如何,请记住,这是一种更像 C 的方法;更好的 C++ 方法是只使用像 std::string 这样的字符串类。

【讨论】:

    【解决方案3】:

    使用 std::string 库。使用起来更容易。与内置的同类产品相比,具有更多的功能。

    【讨论】:

      【解决方案4】:

      TL;DR - 使用 std::string,正如我们在 c++ 中所说的那样。


      编辑:以前,根据 C 标签 (当前已删除)

      根据您的要求,分配字符串文字需要一个指针,无论如何,您不能用数组来做到这一点。#

      如果您使用该指针来存储字符串文字的基地址,则可以。否则,你需要

      • 在使用该指针之前分配内存
      • 完成后释放内存。

      #) 编译时分配数组的基地址不能更改,因此assignment 不起作用。

      【讨论】:

        【解决方案5】:

        不要使用,使用std::string。我(和许多其他人)保证与char*char[] 相比:

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

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-08-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-10-24
            • 2012-11-16
            • 2014-12-20
            相关资源
            最近更新 更多