通过argv []迭代

时间:2018-01-19 02:50:17

标签: c arrays pointers

我是C的新手,我完成了一个小练习,它遍历传递给它的参数中的字母并识别元音。初始代码仅适用于一个参数(argv[1])。我想扩展它以便能够遍历argv[]中的所有参数并重复识别元音的相同过程。

代码:

#include <stdio.h>

int main(int argc, char *argv[])
{
    if (argc < 2) {
        printf("ERROR: You need at least one argument.\n");
        return 1;
    }

    if (argc == 2) {
        int i = 0;
        for (i = 0; argv[1][i] != '\0'; i++) {
            char letter = argv[1][i];

            if (letter == 'A' || letter == 'a') {
                printf("%d: 'A'\n", i);
                //so on
            }
        }
    } else {
        int i = 0;
        int t = 2;
        for (t = 2; argv[t] != '\0'; t++) {
            for (i = 0; argv[t][i] != '\0'; i++) {
                char letter = argv[t][i];

                if //check for vowel
            }

        }

        return 0;
    }
}

我读了this answer,似乎最好的解决方案是使用指针,这个概念我仍然有点摇摇欲坠。我希望有人可以使用这个问题的上下文来帮助我更好地理解指针(通过解释在这个实例中如何使用指针解决手头的问题)。提前谢谢了。

4 个答案:

答案 0 :(得分:4)

  

I was hoping someone could use the context of this question to help me understand pointers better....

在您的计划中:

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

首先,请在此处了解argcargv的内容。

argc(参数计数):是从命令行传入程序的参数数,包括程序名称。

argv(参数向量):指向传递的字符串参数的字符指针数组。

关于argv的几点:

  • argv[0]指向的字符串代表程序名称。

  • argv[argc]是一个空指针。

为了更好地理解,让我们考虑一个例子:

假设您正在将一些命令行参数传递给程序 -

# test have a nice day

test是可执行文件的名称,haveaniceday是传递给它的参数,在这种情况下,参数计数(argc)将为5

参数向量(argv)的内存中视图将是这样的:

      argv                       --
        +----+    +-+-+-+-+--+     |
 argv[0]|    |--->|t|e|s|t|\0|     |
        |    |    +-+-+-+-+--+     |
        +----+    +-+-+-+-+--+     |
 argv[1]|    |--->|h|a|v|e|\0|     |
        |    |    +-+-+-+-+--+     |
        +----+    +-+--+           |
 argv[2]|    |--->|a|\0|            > Null terminated char array (string)
        |    |    +-+--+           |
        +----+    +-+-+-+-+--+     |
 argv[3]|    |--->|n|i|c|e|\0|     |
        |    |    +-+-+-+-+--+     |
        +----+    +-+-+-+--+       |
 argv[4]|    |--->|d|a|y|\0|       |
        |    |    +-+-+-+--+       |
        +----+                   --
 argv[5]|NULL|
        |    |
        +----+

关于字符串(以null结尾的字符数组)的注意事项,它将衰减为指向类型char*的指针。

因为argv(参数向量)是一个指向传递的字符串参数的指针数组。所以,

argv+0 --> will give address of first element of array.
argv+1 --> will give address of second element of array.
...
...
and so on.

我们也可以像这样得到数组第一个元素的地址 - &argv[0]

这意味着:

argv+0 and &argv[0] are same.

类似地,

argv+1 and &argv[1] are same.
argv+2 and &argv[2] are same.
...
...
and so on.

当您取消引用它们时,您将获得它们指向的字符串:

*(argv+0) --> "test"
*(argv+1) --> "have"
....
....
and so on.

类似地,

*(&argv[0]) --> "test"

*(&argv[0])也可以写为argv[0]

表示:

*(argv+0) can also written as argv[0]. 

所以,

*(argv+0) and argv[0] are same
*(argv+1) and argv[1] are same
...
...
and so on.

打印时:

printf ("%s", argv[0]);   //---> print "test"
printf ("%s", *(argv+0)); //---> print "test"
printf ("%s", argv[3]);   //---> print "nice"
printf ("%s", *(argv+3)); //---> print "nice"

由于参数向量的最后一个元素是NULL,当我们访问 - argv[argc]时,我们得到NULL

访问字符串的字符:

argv[1] is a string --> "have"
argv[1][0] represents first character of string --> 'h'

As we have already seen:
argv[1] is same as *(argv+1)

So,
argv[1][0] is same as *(*(argv+1)+0)

要访问字符串“have”的第二个字符,您可以使用:

argv[1][1] --> 'a'
or,
*(*(argv+1)+1) --> 'a'

我希望这可以帮助你更好地理解你的问题背景中的指针。

要识别传递给程序的参数中的元音,您可以执行以下操作:

#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;
}

输出:

#./a.out have a nice day
Vowels in string "have" : a e 
Vowels in string "a" : a 
Vowels in string "nice" : i e 
Vowels in string "day" : a

答案 1 :(得分:2)

您可以使用嵌套for循环遍历所有参数。 argc将告诉您参数的数量,而argv包含数组数组。我还使用了strlen()库中的strings函数。它会告诉你字符串有多长。这样您就可以检查任意数量的参数。您的 if 语句也可以更改为2,argc小于2或大于。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("ERROR: You need at least one argument.\n");
        return 1;
    } else {
        int i, x;
        int ch = 0;
        for (i=1; i<argc; i++) {
            for (x = 0; x < strlen(argv[i]); x++) {
                ch = argv[i][x];
                if (ch == 'A' || ch == 'a' || ch == 'e')
                    printf('Vowel\n');
            }
        }
    }
}

Python等效于嵌套循环

for i in range (0, argc):
    for x in range(0, len(argv[i])):
        ch = argv[i][x];
        if ch in ('A', 'a', 'e'):
            print('Vowel')

答案 2 :(得分:1)

虽然您可以使用多个条件表达式来测试当前字符是否为元音,但创建一个包含要测试的集合的所有可能成员的常量字符串(此处为元音)并循环遍历您的元音串通常是有益的。确定当前字符是否匹配。

您可以简单地使用常量字符串作为要在strchr调用中进行测试的字符串,以确定当前字符是否是该集合的成员。

以下简单地使用循环和指针迭代每个参数中的每个字符,并以类似的方式迭代我们的常量字符串char *vowels = "aeiouAEIOU";中的每个字符,以确定当前字符是否是元音(处理低级和大写形式)。

#include <stdio.h>

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

    int i, nvowels = 0;
    char *vowels = "aeiouAEIOU";

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

    for (i = 1; i < argc; i++) {    /* loop over each argument        */
        char *p = argv[i];          /* pointer to 1st char in argv[i] */
        int vowelsinarg = 0;        /* vowels per argument (optional) */
        while (*p) {                /* loop over each char in arg     */
            char *v = vowels;       /* pointer to 1st char in vowels  */
            while (*v) {            /* loop over each char in vowels  */
                if (*v == *p) {     /* if char is vowel */
                    vowelsinarg++;  /* increment number */
                    break;          /* bail */
                }
                v++;                /* increment pointer to vowels */
            }
            p++;                    /* increment pointer to arg */
        }
        printf ("argv[%2d] : %-16s (%d vowels)\n", i, argv[i], vowelsinarg);
        nvowels += vowelsinarg;     /* update total number of vowels */
    }
    printf ("\n  Total: %d vowles\n", nvowels);

    return 0;
}

示例使用/输出

$ ./bin/argvowelcnt My dog has FLEAS.
argv[ 1] : My               (0 vowels)
argv[ 2] : dog              (1 vowels)
argv[ 3] : has              (1 vowels)
argv[ 4] : FLEAS.           (2 vowels)

  Total: 4 vowles

如果您决定使用strchar中的string.h函数来检查当前字符是否在vowels的集合中,则每个字符的内部循环将减少为:< / p>

        while (*p) {                /* loop over each char in arg     */
            if (strchr (vowels, *p))    /* check if char is in vowels */
                vowelsinarg++;          /* increment number */
            p++;                        /* increment pointer to arg */
        }

仔细看看,如果您有其他问题,请告诉我。

答案 3 :(得分:0)

如果其他人从 Learn C The Hard Way 中得到这个答案,上面使用指针的答案比我们领先一步,因为我们不会在第 15 章之前介绍指针。但是你可以用我们到目前为止所学的知识来做这个额外的功劳。我不会破坏乐趣,但您可以对参数使用 for 循环,对这些单词中的字母使用嵌套的 for 循环;从每个单词中获取一个字母就像 argv[j][i] 一样简单,其中 j 是传递的第 j 个参数,i 是 j 中的第 i 个字母。无需导入头文件或使用指针。我不得不说,当我在第 15 章中提到指针时,我确实回到了 H.S 的回答。