C语言 argv是一个指针数组,因此是否需要使用指向指针的指针来引用它?

brccelvz  于 2022-12-03  发布在  其他
关注(0)|答案(2)|浏览(205)

我正在试着理解用户H.S在这篇文章中写的下面一行代码中使用的指针。有人能帮助我吗?

for (char **pargv = argv+1; *pargv != argv[argc]; pargv++)

整个代码:

#include <stdio.h>

int main(int argc, char *argv[])
{

    if (argc < 2) {
            printf("ERROR: You need at least one argument.\n");
            return -1;
    }

    for (char **pargv = argv+1; *pargv != argv[argc]; pargv++) {
            /* Explaination:
             * Initialization -
             * char **pargv = argv+1; --> pargv pointer pointing second element of argv
             *                            The first element of argument vector is program name
             * Condition -
             * *pargv != argv[argc]; --> *pargv iterate to argv array
             *                            argv[argc] represents NULL
             *                            So, the condition is *pargv != NULL
             *                            This condition (*pargv != argv[argc]) is for your understanding
             *                            If using only *pragv is also okay 
             * Loop iterator increment -
             * pargv++
             */

            printf ("Vowels in string \"%s\" : ", *pargv);
            for (char *ptr = *pargv; *ptr != '\0'; ptr++) {
                    if (*ptr == 'a' || *ptr == 'e' || *ptr == 'i' || *ptr == 'o' || *ptr == 'u'
                    ||  *ptr == 'A' || *ptr == 'E' || *ptr == 'I' || *ptr == 'O' || *ptr == 'U') {
                            printf ("%c ", *ptr);
                    }
            }
            printf ("\n");
    }

    return 0;
}

问题:

1.使用第一个**pargv = argv+1中使用的两个取消引用运算符是因为argv是一个指针数组,因此必须使用指向指针(**pargv)的指针来引用它。此语句正确吗?
1.为什么必须指向argv (argv+1)(&argv[1])的地址,而不是指向其中的值(*argv[1])?
在我看来,指向地址会带来地址的int数,但我知道这样的代码是正确的,那么为什么指向地址会返回里面的值呢?
我试图通过将argv+1替换为argv[1]来更改下面的代码段,因为在我看来,我应该指向数组内部的值,而不是指向指向指向该值的地址,但我从编译器(愚者)中得到了一个错误。

for (char **pargv = argv+1; *pargv != argv[argc]; pargv++)
xdyibdwo

xdyibdwo1#

1.使用第一个**pargv = argv+1中使用的两个取消引用运算符是因为argv是一个指针数组,因此必须使用指向指针(**pargv)的指针来引用它。此语句正确吗?
部分正确。
您引用的**不是两个派生运算符。它是为变量pargv声明的类型的一部分。whole 类型是char **,一个指向char的指针。
因为它和argv的类型是一样的。虽然把argv看作一个数组并不是不合理的,但更正确的理解是它实际上是指向数组(指针的)第一个元素的指针,而不是数组本身。在C中不可能把数组作为函数参数传递--甚至没有办法表达它。
1.为什么必须指向argv (argv+1)(&argv[1])的地址,而不是指向其中的值(*argv[1])?
这不是 * 必须的 *。但是使用指向数组元素的指针是一种迭代数组的方法,这就是所提供的代码正在做的。并且循环的主体通过表达式*pargv使用指向(指针)的值。循环可以重写为:

for (int i = 1; argv[i] != argv[argc]; i++) {
        char **pargv = argv + i;
        // ...

在我看来,指向地址会带来地址的int数,但我知道这样的代码是正确的,那么为什么指向地址会返回里面的值呢?
解引用一个指针可以得到它所指向的对象,不管它是什么类型的。如果被指向的对象本身就是一个指针,也包括在内。这正是所展示的代码中所发生的。
我试图通过将argv+1替换为argv[1]来更改下面的代码段,因为在我看来,我应该指向数组内部的值,而不是指向指向指向该值的地址,但我从编译器(愚者)中得到了一个错误。
argv+1不等价于argv[1]。简单的类型分析可以告诉你:如果定义了两个表达式,则它们具有不同的类型(在示例代码中分别为char **char *)。在这种情况下,argv[1]根据定义 * 等效于*((argv)+1) *,而argv+1等效于&argv[1]

o75abkj4

o75abkj42#

我可能是错的,但请允许我尝试回答你的问题。
1.注意,argv不仅仅是一个指针数组,而是一个指向指针数组的 * 指针 。指针只是指向内存中的一个地址。你的语句是正确的。一个很好的例子是,在main中,你可以用char**argv代替char argv[]的语法,这样什么都不会改变。当你声明一个数组时,在内存中为数组的开头分配地址,并根据数据类型的大小(以字节为单位)分配空间(char,int,long等)和数组的长度。为了进一步说明,当您将参数传递给main(),传递给argv[0]的第一个参数始终是调用文件的参数。例如,如果给定的代码存储在名为“myFile.cpp”的文件中,argv[0]将指向内存中的地址,其中将存储字符“myFile.cpp”的char数组(当然是以空值终止)。argv本身的值是一个指向地址的指针,该地址表示一个地址指针数组,这些地址指针指向实际保存字符值的char数组。
1.问题2的答案直接从问题1得出。你必须指向argv当前所在的位置,因为如果你只得到(argv[1])的值,它实际上会返回一个地址,即你要查找的char数组实际开始的位置!(argv + 1)将返回第一个char[]数组参数开始的地址。
回答您的最后一个问题:argv + 1引用argv,它是一个char
。argv[1]访问argv的第二个元素,它是指向char数组的指针:char
。编译器根据类型定义注意到这一点并返回错误。这就是为什么需要对当前实施执行(argv+1)和(&argv[1])的原因,它们是相同的。argv+1是char**,argv[1]的地址是char**类型,但argv[1]指向的值是char* 类型。
我希望这能有所帮助。我以前从来没有回答过StackOverflow上的问题。请任何人随时纠正任何错误!
编辑:请参阅Andreas Wenzel's注解,以了解数组声明和数组指针声明的说明。

相关问题