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