14

This is my main.c

......
int main(int argc, char **argv)
{
    init_arg(&argc, &argv);
    ......
}

This is my init_arg.c

......
void init_arg(int *argc, char ***argv)
{
    printf("%s\n", *argv[1]);
    ......
}

I compiler it with no error and warning.

I run it:

./a.out include

It get Segmentation fault

When I debug it, I found step printf("%s\n", *argv[1]);

get wrong, It show:

print *argv[1]

Cannot access memory at address 0x300402bfd

I want to know, How to print argv[1] in init_arg() function.

thlgood
  • 1,275
  • 3
  • 18
  • 36
  • 10
    +1 for debugging first and including it in your post! – jedwards Apr 29 '12 at 01:16
  • In GDB when your code crashes run the command bt to see the stack trace leading up to your crash. Read http://crasseux.com/books/ctutorial/argc-and-argv.html for example C program code that handles program arguments. – Rob Kielty Apr 29 '12 at 01:18
  • here's a snippet with examples [http://pastebin.com/SVAZjsXA](http://pastebin.com/SVAZjsXA) – dschulz Apr 29 '12 at 02:02

3 Answers3

19

You need to add a pair of parentheses around (*argv) to change the order of evaluation. The way you currently have it, the [1] is evaluated first, yielding an invalid pointer, which then gets dereferenced, causing undefined behavior.

printf("%s\n", (*argv)[1]);
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 1
    Or, equivalently, you can use `argv[0][1]` (just as long to type, but perhaps slightly more readable). – torek Apr 29 '12 at 02:20
  • 7
    @torek I would refrain from using `argv[0]` in place of `(*argv)`, because what's passed in is a "scalar" pointer (i.e a pointer to a single array), rather than an array of pointers to arrays. I think that the `(*argv)` syntax underscores the notion that we're looking at a pointer to a scalar. – Sergey Kalinichenko Apr 29 '12 at 02:24
  • apparently you fall into the group of people who like to maintain a distinction that C drops. I sympathize! In the early 1980s, I had a colleague who liked to mix pointer and array notation all the time depending on what was convenient. In particular he'd do things like: `time_t now[1]; time(now); ...` instead of `time_t now; time(&now); ...`. :-) – torek Apr 29 '12 at 02:33
  • 1
    "[...] maintain a distinction that C drops" That's a common misconception driven primarily by arrays decaying into pointers when passed into functions. The example that you show is a good and perfectly legitimate one: there is a big difference between treating an array of one item as a pointer and treating a pointer as an array of one item. – Sergey Kalinichenko Apr 29 '12 at 02:39
  • 2
    My point is that the *C language* does not provide any way (in the callee, e.g., function `fn`) to discover whether some pointer argument `T *p` points to a single item (`T var; fn(&var);`) or to the first of `N` sequential items (`T var[N]; fn(var);`). It helps *programmers* to distinguish them, but the language itself does not do that for you. Compare with, e.g., Pascal and Go, which do. – torek Apr 29 '12 at 03:01
  • @torek, are you Chris Torek? If so, stackoverflow became very interesting for me. Love your posts on clc. Thanks! – Alok Singhal Apr 29 '12 at 05:49
  • @Alok: Yes ... I still have access to use(less)net news, but it's mostly too painful these days, with all the spam. :-) – torek Apr 29 '12 at 07:10
13

Argv is already a pointer. Just pass it like this:

init_arg(&argc, argv);

And init_arg should look like this:

void init_arg(int *argc, char **argv) {
    printf("%s\n", argv[1]);
}
alf
  • 681
  • 1
  • 8
  • 19
  • 5
    This answer is correct, but then he could also just pass `argc` rather than `&argc`. Presumably the point to passing both `&argc` and `&argv` is to allow `init_arg` to modify them. – torek Apr 29 '12 at 02:21
  • You can modify them both like this. – alf Apr 29 '12 at 16:35
2

I'm assuming that the reason for passing &argc and &argv in the first place is so that you can update them inside init_arg. Here's how I prefer to write such functions, in general:

/*
 * init_arg: do something useful with argc and argv, and update argc and argv
 * before returning so that the caller can do something else useful that's
 * not shared with all the other callers of init_arg().
 * (this comment of course needs updating to describe the useful things)
 */
void init_arg(int *argc0, char ***argv0) {
    int argc = *argc0;
    char **argv = *argv0;
    ... all the operative code goes here, and then ...
    *argc0 = argc;
    *argv0 = argv;
}

Of course this means you must not do early returns inside init_arg, so there are some tradeoffs, but it sure is a lot easier to work with the same regular old argc and argv inside init_arg.

torek
  • 448,244
  • 59
  • 642
  • 775