繁体   English   中英

C++指针问题

[英]C++ Pointer question

我是 C++ 中指针的新手。 我不确定为什么我需要像char * something[20]这样的指针而不是char something[20][100] 我意识到第二种方法意味着将为数组中的每个元素分配 100 个 memory 块,但第一种方法不会引入 memory 泄漏问题。

如果有人可以向我解释char * something[20]如何定位 memory,那就太好了。

编辑:

我的 C++ Primer Plus 书正在做:

const char * cities[5] = {
"City 1",
"City 2",
"City 3",
"City 4",
"City 5"
}

这不是和刚才人们说的相反吗?

您在 memory 中分配了 20 个指针,那么您将需要通过每一个 go 来动态分配 memory:

something[0] = new char[100];
something[1] = new char[20]; // they can differ in size

并分别删除它们:

delete [] something[0];
delete [] something[1];

编辑:

const char* text[] = {"These", "are", "string", "literals"};

直接在源代码中指定的字符串(“字符串文字”,始终为const char * )与char *完全不同,主要是因为您不必担心它们的 alloc/dealloc。 它们在 memory 中的处理方式也大不相同,但这取决于编译器的实现。

它将为 20 个字符指针分配空间。

它们不会被初始化,所以典型的用法看起来像

char * something[20];
for (int i=0; i<20; i++)
    something[i] = strdup("something of a content");

然后

for (int i=0; i<20; i++)
    if (something[i]) 
       free(something[i]);

你是对的。

  • 您需要通过该数组的每个元素 go 并为每个元素分配一个字符缓冲区。

  • 然后,稍后,您需要通过该数组的每个元素 go 并再次释放 memory。

为什么你会想在 C++ 中对此感到厌烦,这是任何人的猜测。

std::vector<std::string> myStrings(20)有什么问题?

你是对的 - 第一种方法可能会引入 memory 泄漏问题和进行动态分配的开销,以及更多的读取。 我认为第二种方法通常更可取,除非它浪费太多 RAM,或者您可能需要字符串长于 99 个字符。

第一种方法的工作原理:

char* something[20];  // Stores 20 pointers.
something[0] = malloc(100);  // Make something[0] point to a new buffer of 100 bytes.
sprintf(something[0], "hai");  // Make the new buffer contain "hai", going through the pointer in something[0]
free(something[0]);  // Release the buffer.

char* smth[20]不在堆上分配任何内存。 它在堆栈上分配了足够的空间来存储 20 个指针。 这些指针的值是未定义的,因此在使用它们之前,您必须初始化它们,如下所示:

char* smth[20];
smth[0] = new char[100]; // allocate memory for 100 chars, store the address of the first one in smth[0]
//..some code..
delete[] smth[0];

首先,这在 C++ 中几乎不适用。 C++ 中的正常等价物类似于: std::vector<std::string> something;

在 C 中,主要区别在于您可以将每个字符串与其他字符串分开分配。 使用char something[M][N] ,您总是分配完全相同数量的字符串,并为每个字符串分配相同的空间。 这会经常浪费空间(当字符串比您腾出的空间短时),并且不允许您处理比最初腾出空间更多的字符串或更长的字符串。

char *something[20]让您更有效地处理更长/更短的字符串,但仍然只能为 20 个字符串腾出空间。

下一步(如果您喜欢冒险)是使用类似的东西:

char **something;

并单独分配字符串,为指针动态分配空间,所以如果你得到超过 20 个字符串,你也可以处理它。

但是,我要重复一遍,对于大多数实际用途,这仅限于 C。 在 C++ 中,标准库已经具有用于此类情况的数据结构。

C++ 有指针,因为 C 有指针。

为什么我们使用指针?

  1. 跟踪动态分配的 memory。 The memory allocation functions in C ( malloc , calloc , realloc ) and the new operator in C++ all return pointer values.

  2. 模仿传递引用语义(仅限 C)。 在C中,所有的function arguments都是按值传递的; 形参和实参是不同的对象,修改形参不影响实参。 我们通过传递指向 function 的指针来解决这个问题。 C++ 引入了引用类型,它们的用途相同,但比使用指针更简洁、更安全。

  3. 构建动态的、自引用的数据结构。 struct不能包含自身的实例,但可以包含指向实例的指针。 例如下面的代码

     struct node { data_t data; struct node *next; };
    为简单的链表节点创建数据类型; next成员显式指向列表中的下一个元素。 请注意,在 C++ 中,用于堆栈、队列和向量的 STL 容器都在后台使用指针,从而将您与簿记隔离开来。

实际上还有许多其他地方会出现指针,但这些是您使用它们的主要原因。

您的指针数组可用于存储不同长度的字符串,方法是为每个指针分配足够的 memory,而不是依赖于某个最大大小(最终会超过,导致缓冲区溢出错误,并且在任何情况下都会导致内部memory 碎片)。 自然地,在 C++ 中,您将使用string数据类型(它隐藏了 class 背后的所有指针和 memory 管理)而不是从低级别的 API 开始的指针,而不是指向char的指针图片。

我不知道为什么我需要像 char * something[20] 这样的指针而不是 char something[20][100]。 我意识到第二种方法意味着将为数组中的每个元素分配 100 个 memory 块,但第一种方法不会引入 memory 泄漏问题。

如果您仅在本地引用缓冲区,则第二种方法就足够了。

当您将数组名称传递给另一个 function 时,问题就出现了。 当您将char something[10]传递给另一个 function 时,您实际上是在传递char* something ,因为数组长度不是 go。

对于多维 arrays,您可以声明一个 function,它在除一个方向之外的所有方向上都接收一个确定长度的数组,例如foo(char* something[10])

那么为什么使用第一种形式而不是第二种形式呢? 我能想到几个原因:

  1. 您不希望整个缓冲区必须驻留在连续的 memory 中的限制。
  2. 您在编译时不知道您需要每个缓冲区,或者每个缓冲区的长度需要相同的大小,并且您希望在运行时灵活地确定这一点。
  3. 这是一个 function 声明。

字符 * 某事[20]

假设这是 32Bit,这会在堆栈上分配 80 个字节的数据。 每个指针地址 4 个字节,总共 20 个指针 = 4 x 20 = 80 个字节。

指针都未初始化,因此您需要编写额外的代码来分配/释放缓冲区来执行此操作。

它大致看起来像:

[0] [4 字节的未初始化数据来保存指针/内存地址...] [1] [4 字节的...]... [19]

炭化东西[20][100]

在堆栈上分配 2000 个字节。 每个东西 100 个字节,总共 20 个东西 = 100 x 20 = 2000 个字节。

[0] [100 字节保存字符] [1] [100 字节保存字符]... [19]

char *, 具有较小的 memory 开销,但您必须管理 memory。 char[][] 方法具有更大的 memory 开销,但您没有额外的 memory 管理。

无论使用哪种方法,在写入分配的缓冲区时都必须小心,不要超过/覆盖为其分配的 memory。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM