C语言 遍历argv[]

umuewwlo  于 2022-12-03  发布在  其他
关注(0)|答案(4)|浏览(186)

我是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,似乎最好的解决方案是使用指针,这个概念我仍然有点不确定。我希望有人能利用这个问题的上下文来帮助我更好地理解指针(通过解释在这个例子中如何使用指针来解决手头的问题)。提前非常感谢。

0dxa2lsx

0dxa2lsx1#

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

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

First, understand what is argc and argv here.

argc (argument count): is the number of arguments passed into the program from the command line, including the name of the program.
argv (argument vector): An array of character pointers pointing to the string arguments passed.

A couple of points about argv :

  • The string pointed to by argv[0] represents the program name.
  • argv[argc] is a null pointer.

For better understanding, let's consider an example:
Say you are passing some command line arguments to a program -

# test have a nice day

test is the name of the executable file and have , a , nice and day are arguments passed to it and in this case, the argument count ( argc ) will be 5 .
The in-memory view of the argument vector ( argv ) will be something like this:

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|
        |    |
        +----+

A point to note about string (null-terminated character array) that it decays into pointer which is assigned to the type char* .
Since argv (argument vector) is an array of pointers pointing to string arguments passed. So,

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

We can also get the address of the first element of the array like this - &argv[0] .
That means:

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

Similarly,

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

When you dereference them, you will get the string they are pointing to:

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

Similarly,

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

*(&argv[0]) can also written as argv[0] .
which means:

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

So,

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

When printing them:

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

And since the last element of argument vector is NULL , when we access - argv[argc] we get NULL .
To access characters of a string:

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)

To access the second character of string "have", you can use:

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

I hope this will help you out in understanding pointers better in context of your question.
To identify the vowels in arguments passed to program, you can do:

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

Output:

#./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
nnt7mjpx

nnt7mjpx2#

你可以使用嵌套的for循环遍历所有参数。argc会告诉你参数的个数,而argv包含数组的数组。我还使用了strings库中的strlen()函数。它会告诉你字符串的长度。这样你就可以检查任意个数的参数。你的 if 语句也可以改为2个。argc小于2或大于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')
hlswsv35

hlswsv353#

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

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

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 */
        }

把东西看一遍,如果你还有问题,就告诉我。

eqzww0vc

eqzww0vc4#

如果其他人正在学习 Learn C The Hard Way,那么上述使用指针的答案已经远远超出我们了,因为我们要到第15章才会涉及指针。不过,你可以利用我们目前学到的知识来做这件事。我不会破坏这个乐趣,但是你可以使用for循环来处理参数,用嵌套的for循环来处理单词中的字母;从每个单词中得到一个字母就像argv[j][i]一样简单,其中j是传递的第j个参数,i是j中的第i个字母。不必导入头文件或使用指针。我不得不说,当我在第15章提到指针时,我确实回到了H.S的答案。

相关问题