c中的间接水平

Bum*_*Bee 1 c pointers

亲爱的明智的堆栈交换器,我已经把自己长达8个小时的连续思考,但仍然无法找出以下代码的正确解释:

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char** pWords = calloc(10, sizeof(char*));


    *(pWords + 1) = malloc(10);

    strcpy_s(*(pWords + 1), 10, "Test sent\0");

    printf("The string is: %s", *(pWords + 1));

    return 0;

}  
Run Code Online (Sandbox Code Playgroud)

这个输出是:

The string is: Test sent
Run Code Online (Sandbox Code Playgroud)

我已将内存分配解释为:

+-------+-------+-------+-------+......
|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|......
+-------+-------+-------+-------+......
^       ^
|       |
|       |
pointer(let) <-------malloc(10)
|
|
pWords  <------calloc(10, sizeof(char*))  
Run Code Online (Sandbox Code Playgroud)

我基本上不理解涉及间接级别和指针的部分:

首先,pWords被声明为指针的指针.(我认为它就是pointer例如.然后只使用一个"*"符号就会引用这个pointer,对吧?那么pWord在初始化时会指向什么:calloc(10, sizeof(char*))
为什么会*(pWords + 1)用来访问指针的内容那是用两个间接级别声明的**吗?不应该是 **(pWords + 1)吗?

Tob*_*ght 5

在处理C中的字符串时很容易处于混乱状态.字符串在C中并不是真正的一等公民,因此我们有一个使用指向第一个字符指针引用它们的约定.如您所知,字符串的结尾由NUL字符表示.

你分配内存:

char** pWords = calloc(10, sizeof(char*));
Run Code Online (Sandbox Code Playgroud)

在这里,您创建了一个包含指针指向char的10个指针的数组(您将使用它来处理10个字符串).接下来,指出这10个指针中的第二个指向一些新内存:

*(pWords + 1) = malloc(10);
pWords[1] = malloc(10);  /* this is exactly equivalent, and more idiomatic */
Run Code Online (Sandbox Code Playgroud)

现在,您将第二个指针作为目标参数传递给strcpy_s().它将写入指向的char和后续的,用NUL字符结束以标记字符串的结尾:

strcpy_s(pWords[1], 10, "Test sent");
Run Code Online (Sandbox Code Playgroud)

然后你打印字符串; 为此,您将相同的指针(您分配的十个指针中的第二个)传递给printf().

printf("The string is: %s\n", pWords[1]);
Run Code Online (Sandbox Code Playgroud)

几个旁注:

  • 您没有检查所调用的任何函数的返回值,以查看它们是否报告错误.我认为这只是为了保持你的问题简短,但请记住,这种错误检查在C中非常重要 - 如果你不检查,你的程序很可能会以一种神秘而莫名的方式失败.
  • 您通常应该free()malloc()或分配的内存calloc().在程序结束时,放弃它通常是安全的,但是在调试时至少可以选择清理它仍然会发现它很有帮助.当您在代码中的其他位置查找实际内存泄漏时,这可以帮助您.
  • 使用calloc()预留内存指针不保证该指针将是空指针.它很棘手且令人困惑,因为C语言中有一种神奇的功能可以在0您需要时将代码中的代码转换为正确类型的空指针,即使您的目标平台实际上并不将空指针表示为全零位.
  • 如果你给一个strcpy带嵌入式字符串文字的函数\0,它会将该NUL视为字符串的结尾.你可以证明这一点:

    printf("%s\n", "foo\0bar");
    
    Run Code Online (Sandbox Code Playgroud)

    打印将在"foo"后停止,并且不会使用"bar".

  • char **pointer与...完全不一样char *pointer[number].前者是指向a char(并且它可以指向数组)的指针,而后者指向的数组char*.再次,它变得令人困惑,因为malloc()如果我们打算将它作为一个(使用数组索引或其他指针算法),我们倾向于将内存和朋友称为"数组".