2

Sorry if this seems like a basic question. I've been studying for a midterm I have coming up and I can't seem to wrap my head around this. I understand that argv can be used in the command line when you need to send it arguments, but none of the answers my professor gave us seems to make sense.

The parameter argv in the function main(int argc, char *argv[]) is:
A. An array of characters
B. A string
C. An array of pointers to character
D. A character pointer
E. None of the above

I feel like it is none of the above, but it could be because I don't fully understand the concept of argv. Any help would be appreciated!

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
korum
  • 172
  • 1
  • 14
  • 5
    an array of character pointers. ..so `C` – user2736738 Nov 22 '17 at 18:51
  • You are right. Consider that `char** argv` is another way to think about it. If `char*` is an array of characters (a string), then what is `char**`? – AndyG Nov 22 '17 at 18:52
  • @coderredoc: I interpreted it to mean "array of pointers to character" singular. As in, pointers to only one character. Which could never be the case (unless you can pass an empty command line argument) – AndyG Nov 22 '17 at 18:53
  • 1
    @AndyG The syntax `char *ptr` doesn't distinguish between a pointer to one or a pointer to many. It's just a pointer to `char`. – user3386109 Nov 22 '17 at 18:56
  • Imagine that if you'd run your program (let's call it *your_program*) like: `your_program argument1 argumenr2 path/to/argument3 "argument 4"` those **5** strings (`char*`s) would be held by `argv` (that is how you would access them from your program). – CristiFati Nov 22 '17 at 18:56
  • Yes, a pointer points to a single character. Since C has no "string" type, string-like functions are often made to assume that such pointers are pointing to the first character of a sequence in memory. That is, the address of a "string" is really just the address of its first character. – Lee Daniel Crocker Nov 22 '17 at 18:58
  • @user3386109: Yes but think of it in terms of `main` (command line argument). If it was a pointer to a singular character, it would somehow have to be the NUL character. Plus, the standard says that it must contain Nul-terminated multibyte strings... – AndyG Nov 22 '17 at 18:58
  • First lesson, C is not C++ is not C, tag only one language ! Second lesson, you must be able to find information on your own, like you said it's a basic question and there are tons of duplicate on this site. – Stargateur Nov 22 '17 at 19:00
  • @Stargateur I found a few other examples that were similar, however I failed to understand the concept. Even after learning about argv the question my professor gave us seems unclear to me. I just wanted to see if none of the above was correct and I understood properly. – korum Nov 22 '17 at 19:03
  • @NickK Maybe your problem is that you don't understand pointer ? Because [this](https://stackoverflow.com/questions/3024197/what-does-int-argc-char-argv-mean) is clear to me, you should search question about [how pointer work in C](https://stackoverflow.com/questions/tagged/c%20pointers?sort=votes&mode=all). By the way, [this](https://cdecl.org/?q=char+**argv%3B) is the correct answer to what is `argv` in `main()` – Stargateur Nov 22 '17 at 19:08
  • 1
    @NickK E is indeed correct, because `argv` is a pointer to a pointer to a character, which is none of the above. We cannot however know whether you've understood properly and you should ask your professor if you don't understand the concept. – eerorika Nov 22 '17 at 19:12
  • I nominated to reopen because (a) this question is not a duplicate of the purported original, (b) the top answer there does not discuss the type of `argv`, and (c) none of the answers there correctly give the type of `argv`, which is a pointer (not an array) to pointer to `char`. – Eric Postpischil Nov 22 '17 at 20:06
  • @Stargateur: Yes, C and C++ are two different languages, and a question normally should have just one tag or the other. In this case, though, the answer happens to be the same for C and for C++. – Keith Thompson Nov 22 '17 at 21:12
  • @AndyG `char *` is pointer to character. Not an array, and not a string. A `char *` does not contain a string (and the standard does not say that it does). It may point to a character which is in a string. – M.M Nov 22 '17 at 21:26
  • @EricPostpischil I like how one of those who closed as duplicate, also posted the wrong answer in a comment. (currently the top comment) – M.M Nov 22 '17 at 21:28
  • @KeithThompson until C++ or C change this fact and we will have to create a question where all answer will need to be updated and answer differently for C and C++. Duplicate is one of this usecase, you have an question and answers for C++, someone ask for C, and we close the C because C++ answer to the C question, if in the future this is not anymore the case, we can reopen the duplicate question in C. Easy, clean, etc. And I disagree, c standard say that argv will contain pointer to string where c++ standard say that argv with contain pointer to c-string. – Stargateur Nov 22 '17 at 21:34
  • @M.M.: "arguments shall be supplied in argv[0] through argv[argc-1] as pointers to the initial characters of null-terminated multibyte strings (ntmbs s)" is what the C++ standard specifies. – AndyG Nov 22 '17 at 22:28
  • @AndyG Yes, that is consistent with my comment. The `char *` in this case points to the initial character of a string. The `char *` is not an array nor a string, and does not contain a string. – M.M Nov 22 '17 at 22:57
  • @M.M: In C, a `char*` value may be a pointer to a string. (The term *pointer to a string* is defined in the C standard, 7.1.1p1: "A *pointer to a string* is a pointer to its initial (lowest addressed) character.") – Keith Thompson Nov 22 '17 at 23:12
  • @KeithThompson Yes, that is what I am saying. "A pointer to a string" is a different concept to "a string" – M.M Nov 22 '17 at 23:14
  • @Stargateur: As I said, I agree that it should have been tagged with one language or the other. But neither C nor C++ is likely to change in this area. BTW, the C++ standard (ISO 2012) says that `argv[0]` through `argv[argc-1]` are "pointers to the initial characters of null-terminated multibyte strings (NTMBSs)", not "c-strings". In any case, the meaning is essentially identical. – Keith Thompson Nov 22 '17 at 23:18
  • @M.M. I see what you're saying. Splitting hairs a little here, perhaps, but you're right, it points to the first character of the multibyte string. The way your comments read to me made it sound like you really believed there's only ever one character there :-) – AndyG Nov 22 '17 at 23:23

2 Answers2

5

The correct answer is E, none of the above. Although the parameter declaration looks like an array of pointer to char, the rules of C adjust it to pointer to pointer to char, and so do the rules of C++.

Either your instructor mistakenly intended choice C or your instructor designed a question inappropriately tricky for an introductory class, unless it is extra credit.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Thanks a lot Eric! This is exactly what I was looking for! – korum Nov 22 '17 at 20:50
  • "*Either your instructor mistakenly intended C*" -- On first reading, I thought you mean that the instructor meant to ask about C rather than C++. I now realize that you meant choice C. I'll edit. – Keith Thompson Nov 22 '17 at 21:11
  • The citation is [C11 Standard -5.1.2.2.1 Program startup (draft n1570)](http://port70.net/~nsz/c/c11/n1570.html#5.1.2.2.1) and this is an evil question. `argv` is an array of pointers to char, but when passed as a parameter to the function `main` the first level of indirection is converted to a pointer providing a pointer to pointer to char in `main()`. So it really is two distinct questions "What is it?" or "What is its resulting type in `main()` after being passed as a parameter?" question. – David C. Rankin Nov 23 '17 at 00:16
  • @DavidC.Rankin I don't get your point, standard only say "the array members argv[0]", this make me feel strange because standard shouldn't say that `argv` is an array. More, I don't think that C standard want to force an implementation to use an array for `argv`. Or maybe all my life is a lie, I don't know. – Stargateur Nov 23 '17 at 00:42
  • The standard says `"the array members argv[0] through argv[argc-1] inclusive shall contain pointers to strings"`. – David C. Rankin Nov 23 '17 at 02:09
  • @DavidC.Rankin: Undoubtedly it is intended that `argv` point to the members of an array, and `argv[0]` through `argv[argc-1]` are those members. Nonetheless, `argv` is not an array. If I write `int x[3]; int *y = x;`, then `x` is an array, `y` is a pointer to `int`, and `y[0]` is the first member of the array `x`. `y[0]` is **an** array member, but it is not **y’s** array member. `y[0]` is a member of the array `x` because `y` points to `x[0]`, and the subscript operator evaluates to the object that is `x[0]`, so `y[0]` **is** `x[0]`. Further, the question asks about “The parameter `argv`.” – Eric Postpischil Nov 23 '17 at 02:23
  • I'm just a simple person. When the standard says `"the array members argv[0] through argv[argc-1]..."` who am I to argue? I don't mean to mince words either. The array, as I understand it, is an array of pointers. Which is what allows indexing and pointer arithmetic, and why the declaration for main is `int main(int argc, char *argv[])`. I agree with the semantics that for all practical purposes within `main` argv is a *pointer to pointer to char*. Which is also why `int main (int argc, char **argv)` is a valid declaration. Beyond that, I'll defer to your wisdom `:)` – David C. Rankin Nov 23 '17 at 04:15
2

I think your professor wants C, even though the pedanticly correct answer is E. The data referred to by argv is an array, but the variable itself is a pointer. I think it's worth exploring why, because it has nothing to do with the type of array or main.

Consider an array of integers,

int a[] = { 1, 2, 3 };

This allocates 3 adjacent integers. The size of the array is sizeof(int) * 3.

Now let's write a function to double the values of each member,

void F( int m[], size_t n ) {
    for( int i=0; i < n; i++ ) {
        m[i] *= 2;
    }

int main( int argc, char *argv[] ) {
    F(a, sizeof(a)/sizeof(a[0]));
    return EXIT_SUCCESS;
}

What is m? It's declared to be an array, but it's really a pointer: sizeof(m) == sizeof(int*). That's because C doesn't pass arrays as function arguments. The term of art in C is that an array argument decays to a pointer.

It sorta kinda doesn't matter, because C syntax hides a host of sins, er, differences. You can use the subscript notation with both arrays and pointers. For that reason, our function F can treat m almost like an array, except that it requires the length, because it can't derive the length from the size, because the size is the size of the pointer.

Let me say that a different way. When F is called, the "arguments on the stack" are not the values of a, namely 1, 2, and 3. There is just one such argument, a pointer to the first element of a (often thought of as the address of the first element). You can use that pointer as an array partly because the name of an array also refers to the address of the first element.

Now let's back up to your friend argv. Array, or pointer? Let's say your program foo is invoked on the command line:

$ foo sam I am

What does the operating system do? Somehow, it has to pass those 4 strings (character arrays) to your program. Somewhere, it has to allocate contiguous space for them. Conceptually, the shell might do something like:

char **args = calloc(5, sizeof(char*));
args[0] = "foo"; 
args[1] = "sam"; 
args[2] = "I"; 
args[3] = "am"; 

or,

char args[5] = { "foo", "sam", "I", "am" };

Either way, it could pass args to execv(3), invoking your main, and passing you a ... pointer. After all, it can't pass you an array, right?

Please note args must be an array. If it weren't argv[1] would be meaningless.

(Why 5 elements, you ask, when there are only 4 arguments? There's a rule -- C or Posix, i don't remember -- that the last element in the array (!) must be a NULL pointer.)

Array or pointer? Wave or particle? Where you stand depends on where you sit. argv is pointer a to char*, certainly. By definition, though, it's a pointer to the start of an array of char*.

James K. Lowden
  • 7,574
  • 1
  • 16
  • 31
  • You confuse array and pointer in a question that ask about this difference ;). "The data referred to by `argv` is an array," wrong, "Please note `args` must be an array.", wrong. That remind me some funny mail, https://lkml.org/lkml/2015/9/3/428. "By definition, though, it's a pointer to the start of an array of char*", nope – Stargateur Nov 23 '17 at 00:01
  • I'm not confused. I described how an array is passed as a pointer. While exec(3) is free to construct an array of pointers for argv, or accept such an array and pass it verbatim (or copy it) the fact remains that argv points to the start of an array, else the locations up to argv[argc-1] wouldn't be valid. If you think that's not so, you haven't offered any evidence. – James K. Lowden Nov 23 '17 at 01:13
  • First `exec()` family are not a part of C standard. "argv points to the start of an array, else the locations up to argv[argc-1] wouldn't be valid.", You confuse a pointer that contain the address of contigus numbers of element type and an array. An array is only with the syntax "[5](fixed size) or [n](VLA) or [](automatic size at compilation time only if initialized)", `char **args;` is not an array, `char *argv[];` is not an array, `char *args[5]` is not an array but a pointer to an array of size 5. `int *p = (int [3]){1, 2, 3};` is a pointer. http://port70.net/~nsz/c/c11/n1570.html#6.2.5p20 – Stargateur Nov 23 '17 at 02:34
  • "`char *args[5]` is not an array but a pointer to an array of size 5". Really? What is `sizeof(args)` in that case? If the answer surprises you, I can only refer you to K&R. I'm sorry if "points to the start of an array" is unclear; to me your description is less clear because redundant, but equivalent. – James K. Lowden Nov 23 '17 at 15:42
  • Oh yeah, my bad `char *argv[5];` is an array of size 5 of pointer. I confuse with `char (*argv)[5];` Whatever, `char *argv[];` is not an array. Array and pointer are not equivalent. Sorry, I'm not a good english speaker, so I can't explain it very well. – Stargateur Nov 23 '17 at 15:47