I'm new to C and I completed a small exercise that iterates through the letters in an argument passed to it and identifies the vowels. The initial code only worked for one argument (argv[1]
). I want to expand it to be able to iterate through all arguments in argv[]
and repeat the same process of identifying vowels.
The code:
#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;
}
}
I read this answer and it seems the best solution is to use pointers, a concept I'm still a bit shaky with. I was hoping someone could use the context of this question to help me understand pointers better (by explaining how using pointers in this instance solves the problem at hand). Many thanks in advance.
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
You can use nested for loops to loop through all arguments. argc
will tell you number of arguments, while argv
contains the array of arrays. I also used strlen()
function from strings
library. It will tell you how long a string is. This way you can check for any number of arguments. Your if statement can also be changed to just 2, either argc
is less than 2 or more than.
#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 Equivalent for the nested loop
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')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With