I am trying to understand the pointer used in line of code below written by the user H.S in this post. Could anyone help me?
for (char **pargv = argv 1; *pargv != argv[argc]; pargv )
The whole code:
#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;
}
Questions:
The two dereference operators used in the first
**pargv = argv 1
are used because the argv is an array of pointers, therefore it is necessary to use a pointer to a pointer (**pargv) to refer to it. Is this statement correct?Why is it necessary to point to the address of the argv
(argv 1)
or(&argv[1])
and not the value (*argv[1]) that is inside it?
In my mind pointing to the address would bring the int number of the address, but I know the code is correct this way. So why pointing to the address return the value inside?
I have tried to change the piece of code below by replacing the argv 1
for argv[1]
because in my mind I should point to the value inside of the array and not to the address that leads to the value but I got an error from the compiler (GCC).
for (char **pargv = argv 1; *pargv != argv[argc]; pargv )
CodePudding user response:
Horrible code
*pargv != argv[argc]
is undefined behaviour. If for some reason you want to use pointers it should be
for (char **pargv = argv 1; pargv <= argv argc -1; pargv ) {
The two dereference operators used in the first **pargv = argv 1
It is not derefence operator in this case. It defines pointer to pointer to char variable pargv
but I got an error from the compiler (GCC).
Because argv[i] == *(argv i)
not argv i. Indexing dereferences the pointer. If you want to use index you will need to use &
operator to take reference to it char **pargv = &argv[1];
CodePudding user response:
I could be wrong here, but allow me to attempt to answer your questions.
Be careful here, argv is not just an array of pointers, but a pointer to an array of pointers. A pointer just points to an address in memory. Your statement is correct. A good example to test this is that in main, instead of using the syntax of char *argv[], you could substitute it with char **argv and nothing would change. This is because an array is just a pointer to an address in memory where the array begins. When you declare an array, an address is assigned in memory for the beginning of the array, and space is allocated based on the size of data type in bytes(char, int, long, etc) and the length of the array. To further clarify, when you pass in arguments to main(), the first argument passed to argv[0] is always that of the calling file. If your code given was stored in a file called "myFile.cpp" for example, argv[0] will point to an address in memory where an array of char the characters "myFile.cpp" will be stored (null-terminated of course). The value of argv itself is a pointer to an address that represents an array of address pointers that point to char arrays that actually hold the character values.
The answer for 2 goes directly off of question 1. You have to point to the value of where argv currently is because if you just get the value of (*argv[1]) it actually will return an address to where the char array you're looking for actually starts! (argv 1) will return the address of where the first char[] array argument begins.
To answer you final questions: argv 1 is referring to argv, which is a char**. argv[1] accesses the the second element of argv which is a pointer to a char array: char* . The compiler notices this based on the type definitions and returns an error. This is why you need to do (argv 1) and (&argv[1]) with your current implementation, they are the same. argv 1 is a char** and the address of argv[1] is of type char**, but the VALUE of what argv[1] points to is of char*.
I hope this helps. I've never answered a question on StackOverflow before. Please anyone feel free to correct any errors!
CodePudding user response:
- The two dereference operators used in the first
**pargv = argv 1
are used because the argv is an array of pointers, therefore it is necessary to use a pointer to a pointer (**pargv) to refer to it. Is this statement correct?
Partially correct.
The **
you're referring to is not two derference operators. It is part of the type being declared for variable pargv
. The whole type is char **
, a pointer to a pointer to char
.
And that's used because it is the same type as argv
. Although it's not unreasonable to think about argv
as an array, it is more correct to understand that it is in fact a pointer to the first element of an array (of pointers), not an array itself. It is not possible in C to pass an array as function argument -- there is no way even to express it.
- Why is it necessary to point to the address of the argv
(argv 1)
or(&argv[1])
and not the value (*argv[1]) that is inside it?
It is not necessary. But using pointers to array elements is one way to iterate over an array, which is what the code presented is doing. And the body of the loop does use the pointed-to (pointer) value, via the expression *pargv
. The loop could be rewritten as:
for (int i = 1; argv[i] != argv[argc]; i ) {
char **pargv = argv i;
// ...
In my mind pointing to the address would bring the int number of the address, but I know the code is correct this way. So why pointing to the address return the value inside?
Dereferencing a pointer gets you the object it points to, of whatever type that is. Including if the pointed-to object is itself a pointer. That's exactly what happens in the code presented.
I have tried to change the piece of code below by replacing the
argv 1
forargv[1]
because in my mind I should point to the value inside of the array and not to the address that leads to the value but I got an error from the compiler (GCC).
argv 1
is not equivalent to argv[1]
. Ever. Simple type analysis can tell you that: if both expressions are defined then they have different types (char **
and char *
, respectively, in the example code). In that case, argv[1]
is equivalent to *((argv) 1)
by definition, and argv 1
is equivalent to &argv[1]
.