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