字符指针数组

8
我正在查看一些我没有编写的代码,并想要帮助理解其中的一个元素。代码存储字符数组,创建指向这些数组的指针(将指向数组地址的指针分配)。看起来它然后创建一个数组来存储这些字符指针地址,我只是想要一些关于我所看到的东西的澄清。我还对在创建数组时使用双重(**)感到困惑。
下面是一个精简和简化的例子,以便更好地理解。
char eLangAr[20] = "English";
char fLangAr[20] = "French";
char gLangAr[20] = "German";

char* eLangPtr = eLangAr;
char* fLangPtr = fLangAr;
char* gLangPtr = gLangAr;


char **langStrings [3]=
{
    &eLangPtr,
    &fLangPtr,
    &gLangPtr
};

当使用数组时,他们将其作为参数传递给函数。
menu (*langStrings[0]);

所以,这个想法是将字符数组值“英语”传递给函数,但我不知道如何做到。他们将存储在langStrings函数位置0处的值的副本传递给菜单函数,这将是eLandPtr的地址?如果有人能用英语解释一下这个过程,那就太好了。可能只是因为经历了漫长的一天,但我的头脑根本无法理清这一点。


2
“English” 的数组值不会传递给函数。它的指针被传递。langStrings[0] 的值为 &eLangPtr。取消引用后,*langStrings[0] 将给出 &eLangPtr 指向的内容,即 eLangAr[20] 的地址。** 是因为 &eLangPtr 是一个 char 指针的地址。所以 langStrings 是一个指向 char 指针的指针数组,即 char ** - lurker
4
写这段话的人太过复杂了。那些 LangPtr 变量其实并不必要,因为数组会自动退化成指针。 - hegel5000
2
@hegel5000 它无法编译 https://ideone.com/YpbnEA - Killzone Kid
2
当你取一个数组的地址时,数组不会退化为指针,这是唯一的例外。因此 char **langStrings [3]= { &eLangAr, ...char **langStrings [3]= { &eLangPtr, ... 是不同的。 - john
2
@hegel5000 显然是一名三星级程序员,http://wiki.c2.com/?ThreeStarProgrammer - john
显示剩余7条评论
4个回答

8
您说得没错,langStrings 包含字符数组的指针指针。因此每个 langString[i] 指向一个指针,该指针指向一个数组,该数组包含一种语言的名称。
正如其他人指出的那样,这看起来有点笨拙。我会详细说明: char eLangAr[20] = "English"; 是一个长度为20的字符数组,名称“English”被复制到其中。我不希望变量eLangAr包含除这种语言之外的其他内容,因此不需要使用数组;常量就足够了。 char **langStrings [3]= ... 在这里,只需要一个间接引用(一个*)就足够了,因为似乎没有必要让指针随意指向其他东西(随机洗牌语言?)。
总之,只需要以下代码就足够了:
const char *langStrings [3]=
{
    "English",
    "French",
    "German"
};

(请注意, const 表示字符串现在是只读的常量/文字。)
给定的代码有用的地方是当这些语言名称在不同语言中拼写不同时。 所以“英语”,“法语”,“德语”变成了“Engels”,“Frans”,“Duits”。 但是,还有一个间接层次过多,下面的内容就足够了:
char *langStrings [3]=
{
    aLangArr,
    fLangAr,
    gLangAr
};

1

好的,开始吧。 **ptrToptr 表示指向指针的指针。最简单的想法是将其视为二维矩阵——解引用一个指针会将整个矩阵解析为矩阵中的一行。在此之后再次解引用第二个指针将给出矩阵中的一个值。

这个声明:

char eLangAr[20] = "English";

声明一个长度为20的字符类型数组,其中包含字符'E'、'n'、'g'、'l'、'i'、's'、'h'和'\0'。因此它(可能)是以空字符结尾的,但不是满的(末尾有一些空字符)。您可以使用以下代码将指针设置为其开头:
char* englishPtr = &eLangAr[0]

如果您取消引用englishPtr,它将返回值'E'。这是一个指针:

char* eLangPtr = eLangAr;

指向数组本身(不一定是第一个值)。
如果您查看
*langStrings[0]

您将看到它意味着在langStrings [0]中的指针内容(取消引用*)。 langStrings [0]是eLangPtr的地址,因此取消引用它会给出eLangPtr。而eLangPtr是指向包含“英语”的eLangAr数组的指针。
我猜这个函数想要能够写入eLangAr,所以它让它指向一个不同的单词,而不是覆盖“英语”本身。它可以直接在内存中覆盖字符,但我猜它想要保护那些单词。

请注意,赋值语句中不需要使用&[0]。只需写成char* englishPtr = eLangAr即可。是的,它将始终指向第一个字符,也就是E - Paul Ogilvie
谢谢,我的 C 语言有点生疏了。我可能在想指向指针的问题。 - Pam

0

** 表示指向指针。它用于当您必须为另一个指针存储指针时。

eLangPtr 的值将是指向 eLangAr 的指针,其值为“英语”。


0

这里:

char eLangAr[20] = "English";

创建了一个数组。它的容量为20个char,包含8个字符——单词“English”和终止的NULL字符。由于它是一个数组,因此可以在期望指针的上下文中使用它——感谢数组到指针的衰减,它将构造一个指向数组第一个元素的指针。这是在这里完成的:

char* eLangPtr = eLangAr;

这与以下内容相同:

char* eLangPtr = &eLangAr[0]; // explicitly get the address of the first element

现在,虽然char*表示指向字符的指针(这意味着它指向单个char),但char**表示指向char*指针的指针。

区别在于:

char text[] = "Text";
char* chPointer = &ch[0];
char** chPointerPointer = &chPointer; // get the address of the pointer

std::cout << chPointer; // prints the address of 'text' array
std::cout << *chPointer; // prints the first character in 'text' array ('T')
std::cout << chPointerPointer; // prints the address of 'chPointer'
std::cout << *chPointerPointer; // prints the value of 'chPointer' which is the address of 'text' array
std::cout << *(*chPointerPointer); // prints the first character in 'text' array ('T')

正如您所看到的,这只是一个额外的间接层。

指向指针的指针与“一级”指针使用相同的原因-它们允许您获取指针的地址并将其传递给可能会写入某些内容以修改原始指针内容的函数。

在这种情况下,这是不必要的,以下内容已足够:

const char *langStrings [3]=
{
    eLangPtr,
    fLangPtr,
    gLangPtr
};

然后:

menu (langStrings[0]);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接