C++指针问题

C++ Pointer question

本文关键字:问题 指针 C++      更新时间:2023-10-16

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

如果有人能向我解释char * something[20]是如何定位内存的,那就太好了。

编辑:

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

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

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

您在内存中分配了20个指针,然后您需要遍历其中的每一个指针来动态分配内存:

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 *有很大不同,主要是因为您不必担心它们的分配/释放。它们在内存中的处理通常也非常不同,但这取决于编译器的实现。

你说得对。

  • 您需要遍历该数组的每个元素,并为每个元素分配一个字符缓冲区。

  • 然后,稍后,您需要遍历该数组的每个元素,然后再次释放内存。

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

std::vector<std::string> myStrings(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]);

你是对的-第一种方法可能会引入内存泄漏问题和动态分配的开销,以及更多的读取。我认为第二种方法通常更可取,除非它浪费了太多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. 跟踪动态分配的内存C中的内存分配函数(malloccallocrealloc(和C++中的new运算符都返回指针值。

  2. 模拟传递引用语义(仅限C(在C中,所有函数参数都是通过值传递的;形式参数和实际参数是不同的对象,修改形式参数不会影响实际参数。我们通过向函数传递指针来解决这个问题。C++引入了引用类型,它们具有相同的目的,但比使用指针更干净、更安全。

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

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

实际上,还有几十个其他地方会出现指针,但这些都是你使用它们的主要原因。

指针数组可以用于存储不同长度的字符串,方法是为每个字符串分配足够的内存,而不是依赖于某个最大大小(最终会超过该大小,导致缓冲区溢出错误,并且在任何情况下都会导致内部内存碎片(。当然,在C++中,您会使用string数据类型(它将所有指针和内存管理隐藏在类API后面(,而不是指向char的指针,但有人决定从低级细节而不是全局图开始,这会让您感到困惑。

我不是确定为什么我需要像char这样的指针*与木炭相反的东西某物[20][100]。我意识到第二种方法意味着100将为分配内存块数组中的每个元素,但是第一种方法不是介绍内存泄漏问题。

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

当您将数组名称传递给另一个函数时,就会出现问题。当您将char something[10]传递给另一个函数时,实际上您传递的是char* something,因为数组长度与行程不一致。

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

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

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

char*something[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*的内存开销较小,但您必须管理内存。char[][]方法有更大的内存开销,但没有额外的内存管理。

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