C 中的 char 数组比 char 指针更有效吗?

Gar*_*ett 5 c arrays pointers dynamic-memory-allocation

我试图理解这两个 char 声明之间的内在区别:

char* str1;
char str2[10];
Run Code Online (Sandbox Code Playgroud)

我知道 usingchar*给出了指向 中第一个字符的指针str1,而char[10]结果是一个长度为 10 个字节的数组(因为char是一个字节......我记得在某些编码中它可以更多,但我们假设一个字节把事情简单化)。

我的问题是,当实际为它们赋值时,数据显然必须存储在某个地方,并且在char[10]我们预先告诉编译器分配十个字节的情况下,而在char*我们实际上只是说分配一个指向单字节。但是如果我们分配的字符串str1超过一个字节会发生什么,它是如何分配的呢?还需要做多少工作才能适当分配?另外,如果我们想重新分配str1比之前分配的更长的值,会发生什么,如何分配?

由于处理 时从编译器的角度来看存在不确定性,当我提前知道长度或想要限制开始时的长度时,char pointers使用 a 是否更有效?char array

Lun*_*din 7

在讨论一般性能时,分配、访问时间和复制时间是分开的。您似乎最关心的是分配。

但这里存在很多误解。数组是用来存储的。指针用于指向存储在其他地方的东西。您不能在指针中存储任何数据,只能存储在其他地方分配的数据的地址。

因此,比较指针或数组几乎是无意义的,因为它们是不同的东西。类似于“我应该住在街道地址的房子里还是应该住在标明我的街道地址的标志中”。

我知道使用 char* 给出了指向 str1 中第一个字符的指针

不,它给出了一个指向分配在其他地方的单个字符的指针。尽管在您为其分配地址之前它不会指向任何有意义的地方。对于数组,它通常会设置为指向数组的第一个字符。

我记得在某些编码中它可以更多

不,根据定义,字符始终为 1 个字节。一些外来系统可能有 16 位/字节等。除非您对特殊的 DSP 等进行编程,否则这并不重要。至于其他字符编码,则wchar_t完全是另一个主题。

而在 char* 的情况下,我们实际上只是说分配一个指向单个字节的指针

不,我们告诉它为指针本身分配空间。其大小通常在 2 到 8 字节之间,具体取决于特定系统的地址总线宽度。

但是,如果我们分配给 str1 的字符串超过一个字节,会发生什么情况,它是如何分配的呢?

不过你喜欢就好。您可以将其分配给只读字符串文字、静态存储持续时间变量、本地自动存储变量或动态分配的变量。指针本身不知道也不关心。

还需要做多少工作才能适当分配?

这取决于你想要分配什么。

因为处理 char 指针时从编译器的角度来看存在不确定性

这是什么不确定性?指针就是指针,编译器对待它们与其他变量没有太大区别。

当我提前知道长度或想要限制开始长度时,使用 char 数组是否更有效?

你需要使用数组,因为数据不能凭空存储。同样,数据不能存储在“指针中”。


Joh*_*ode 6

但是,如果我们分配给 str1 的字符串超过一个字节,会发生什么情况,它是如何分配的呢?

str1最终必须指向另一个数组char- 是否是自动分配的,例如

char buffer[10];
char *str1 = buffer; // equivalent to &buffer[0]
Run Code Online (Sandbox Code Playgroud)

或动态地:

char *str1 = malloc( sizeof *str1 * 10 );
Run Code Online (Sandbox Code Playgroud)

或通过其他方法。所有存储都是内存中某个对象str1的地址。char您实际上并没有将任何内容保存到str1,而是将其保存到str1 指向 的任何内容。假设有以下声明:

char *str;
char buffer[10];
Run Code Online (Sandbox Code Playgroud)

我们的记忆中是这样的:

      char *            char
      +---+             +---+
 str: | ? |     buffer: | ? | buffer[0]
      +---+             +---+
                        | ? | buffer[1]
                        +---+
                         ...
                        +---+
                        | ? | buffer[9]
                        +---+
Run Code Online (Sandbox Code Playgroud)

首先,我们将 的第一个元素的地址分配bufferstr1

str = buffer;
Run Code Online (Sandbox Code Playgroud)

现在我们的图片看起来像这样:

      char *            char
      +---+             +---+
 str: |   | --> buffer: | ? | buffer[0]
      +---+             +---+
                        | ? | buffer[1]
                        +---+
                         ...
                        +---+
                        | ? | buffer[9]
                        +---+
Run Code Online (Sandbox Code Playgroud)

buffer现在我们可以使用以下方法存储字符串str

strcpy( str, "foo" );
Run Code Online (Sandbox Code Playgroud)

给我们

      char *            char
      +---+             +---+
 str: |   | --> buffer: |'f'| buffer[0]
      +---+             +---+
                        |'o'| buffer[1]
                        +---+
                        |'o'| buffer[2] 
                        +---+
                        | 0 | buffer[3]
                        +---+
                         ...
                        +---+
                        | ? | buffer[9]
                        +---+
Run Code Online (Sandbox Code Playgroud)

“那么,”你会问自己,“为什么我们要为指针烦恼?为什么不直接存储字符串buffer?这样不是更高效吗?”

是的,通常我们会直接存储到buffer并避免指针的开销(如果这是一个选项)。然而,有时这不是一个选择。我们在以下情况下通过指针进行工作:

  • 数组是动态分配的 - 在这种情况下我们别无选择,只能通过指针:
    char *str = malloc( sizeof *str * 10 );
    strcpy( str, "foo" );
    
    Run Code Online (Sandbox Code Playgroud)
  • 数组作为参数传递给函数 - 由于衰减规则,当您将数组作为函数参数传递时,函数实际接收到的是指向第一个元素的指针(这对于所有数组类型都是如此,而不仅仅是字符数组):
    void foo( char *str, size_t max_size )
    {
      strncpy( str, "this is a test", max_size );
      str[max_size-1] = 0;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 我们使用指针来迭代char []or数组char *
    char table[][10] = { "foo", "bar", "bletch", "blurga", "" };
    ...
    char *p = table[0];
    while ( strlen( p ) )
      printf( "%s\n", p++ );
    ...
    
    Run Code Online (Sandbox Code Playgroud) 当然,我们可以只使用数组表示法,而不用担心指针:
    size_t i = 0;
    while ( strlen( table[i] ) )
      printf( "%s\n", table[i++] );
    
    Run Code Online (Sandbox Code Playgroud) 有时使用数组表示法更有意义,有时使用指针更有意义 - 取决于当前的问题。

  1. 除非它是sizeofor 一元运算&符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则“T`的 N 元素数组”类型的表达式将被转换,或“衰减”,到“指向‘T’的指针”类型的表达式,表达式的值将是数组第一个元素的地址。