Strange Error after printing argv values

M

Matt

Hello. I've got a very strange problem. Basically I have a programme
where I wish to view all the strings in the argv array so I can see
what arguments are being passed to the programme.

However, when I insert the following line at the start of a FOR loop
early on the in the programme to do this:

printf("\nCommand line arguement %d: %s. \n", i , argv );

I get back the first 3, then I get a segmentation fault followed by
all kinds of errors. When I comment this line out he programme runs
with no problems.

It seems that reading and outputting the values of argv is changing
something in the programme. How can just outputting the values of argv
to the screen cause this?

Kind Regards,

Matt
 
K

Kenny McCormack

Hello. I've got a very strange problem. Basically I have a programme
where I wish to view all the strings in the argv array so I can see
what arguments are being passed to the programme.

However, when I insert the following line at the start of a FOR loop
early on the in the programme to do this:

printf("\nCommand line arguement %d: %s. \n", i , argv );


I assume that you did:

for (i=1; i<=3; i++)
printf("\nCommand line arguement %d: %s. \n", i , argv );

When you should have done:

for (i=0; i<argc; i++)
printf("\nCommand line argument %d: %s. \n", i , argv );
 
M

mmcconnell17704

Maybe you're trying to print too many? The loop should be
for (i = 0; i < argc; ++i) { ... }
For example, in the call
myprogram 1776.0 xyzzy
argc will be 3. argv[0] will be myprogram, argv[1] will be 1776.0,
and argv[2] will be xyzzy.
 
O

Old Wolf

[email protected] (Kenny McCormack) said:
When you should have done:

for (i=0; i<argc; i++)
printf("\nCommand line argument %d: %s. \n", i , argv );


The arguments can still be NULL; in particular,
argv[0] could be null. This happens even on the
most common OS's; e.g. when a task is invoked via
a call like execv where the caller specifies the
arguments, including argv[0].

So you should write:

for (i=0; i<argc; i++)
if ( argv )
printf("Command line argument %d: %s.\n", i , argv );

or perhaps :

for (i=0; i<argc; i++)
printf("Command line argument %d: %s.\n",
i , argv ? argv : "<null>");
 
A

Al Balmer

Hello. I've got a very strange problem. Basically I have a programme
where I wish to view all the strings in the argv array so I can see
what arguments are being passed to the programme.

However, when I insert the following line at the start of a FOR loop
early on the in the programme to do this:

printf("\nCommand line arguement %d: %s. \n", i , argv );

I get back the first 3, then I get a segmentation fault followed by
all kinds of errors. When I comment this line out he programme runs
with no problems.

It seems that reading and outputting the values of argv is changing
something in the programme. How can just outputting the values of argv
to the screen cause this?

It can't. However, fetching the argv can certainly cause a
segfault, if i is greater than or equal to the number of arguments you
actually have. I would guess that you're invoking the program with two
or less arguments (argv[0]) will be the name in most cases, but not
guaranteed.) The typical name for the count variable is argc. A
typical program will be something like

#include <stdio.h>

int main(int argc, char *argv[])
{
..
..
..
int i;
for (i = 0; i < argc; ++i)
{
/* do something with argv, such as: */
printf("\nCommand line argument %d: '%s'. \n", i , argv );
}
..
..
..
}
 
R

Robert Gamble

[email protected] (Kenny McCormack) said:
When you should have done:
for (i=0; i<argc; i++)
printf("\nCommand line argument %d: %s. \n", i , argv );


The arguments can still be NULL; in particular,
argv[0] could be null. This happens even on the
most common OS's; e.g. when a task is invoked via
a call like execv where the caller specifies the
arguments, including argv[0].


While this is certainly true it breaks conformity with Standard C
(except when argc is 0). It is certainly not bad practice to write
code to anticipate such possibilities but if the values of the program
parameters are coerced in such a way one should expect to suffer the
consequences.

Robert Gamble
 
M

Matt

The relevant part of my code reads as follows:

for ( i = 0 ; i < argc ; i++ )

{

printf("\narg = %d\n" , argc );

printf("\nCommand line arguement %d: %s. \n", i , *argv );

and the stdio.h header is loaded at the start. You may notice I have
added a * before the argv as I realised I wished to print the value
the pointer points at, was this a correct thing to do?

Something else that is rather worrying is that if I comment this bit
out, later in the programme when it tries to read argv[1], I get
another segmentation fault. I assume this only happens when argv[1] =
NULL, but since I am almost certain the programme to supplied with at
least one argument, and that the error occurs when I try to print
argv[0] (which is the one thing that cannot be NULL!), something else
must be wrong here.

Kind Regards,

Matt
 
M

Matt

I assume that you did:
for (i=1; i<=3; i++)
printf("\nCommand line arguement %d: %s. \n", i , argv );

When you should have done:

for (i=0; i<argc; i++)
printf("\nCommand line argument %d: %s. \n", i , argv );


The latter is what I did, as shown in my previous post.
 
O

Old Wolf

The relevant part of my code reads as follows:

printf("\nCommand line arguement %d: %s. \n", i , *argv );

and the stdio.h header is loaded at the start. You may notice I have
added a * before the argv as I realised I wished to print the value
the pointer points at, was this a correct thing to do?


No. Read the documentation for printf, specifically
%s. You will see that it expects a pointer to char.
This is because the printf function has to be able
to increase the pointer until it reaches the end-
of-string marker.

As it stands, your code causes undefined behaviour
because you did not pass a pointer-to-char for
%s, so anything could happen. A segfault is most
likely; garbage output is another possibility.
Something else that is rather worrying is that if I comment this bit
out, later in the programme when it tries to read argv[1], I get
another segmentation fault.

Post the exact program that causes the fault.
I assume this only happens when argv[1] = NULL

Why assume? Add in code to check if this is happening.
 
M

Matt

No. Read the documentation for printf, specifically
%s. You will see that it expects a pointer to char.
This is because the printf function has to be able
to increase the pointer until it reaches the end-
of-string marker.

As it stands, your code causes undefined behaviour
because you did not pass a pointer-to-char for
%s, so anything could happen. A segfault is most
likely; garbage output is another possibility.

Just before your reply I got rid of the *, and now I get the value of
argv[0] printed to the screen, followed by a segmentation fault.
Something else that is rather worrying is that if I comment this bit
out, later in the programme when it tries to read argv[1], I get
another segmentation fault.

Post the exact program that causes the fault.

The programme in its entirity is far too large I'm afraid. Basically
the bit of troublesome code arises from my implementation of the
getopt_long function from the GNU library:

http://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Options.html#Getopt-Long-Options

with the example code:

http://www.gnu.org/software/libc/ma...ption-Example.html#Getopt-Long-Option-Example

My implemtation is as follows:

for ( i = 0 ; i < argc ; i++ )

{

printf("\nargc = %d\n" , argc );

printf("\nCommand line arguement %d: %s. \n", i , argv );

while (1)

{

static struct option long_options[] =

{

// These options set a flag.
{"stack" , no_argument , &stack_mode , 1}, // Enable
stack (convolution) mode

// These options don't set a flag. We distinguish them
by their indices.
{"configfile" , required_argument , 0 , 'c'},
{0 , 0 , 0 , 0}

};

// getopt_long stores the option index here.
int option_index = 0;

*getopt_val = getopt_long (argc, argv, "c:", long_options,
&option_index);

// Detect the end of the options.
if (*getopt_val == -1)

{

break;

}

switch (*getopt_val)

{

case 0:
// If this option set a flag, do nothing else now.
if ( long_options[option_index].flag != 0)

{

break;

}

printf ("option %s", long_options[option_index].name);

if (optarg)

{

printf (" with arg %s", optarg);

}

printf ("\n");
break;

case 'c':
printf ("option -c with value `%s'\n", optarg);
break;

case '?':
/* getopt_long already printed an error message. */
break;

default:
abort ();

}

}

/* Print any remaining command line arguments (not options). */
if (optind < argc)

{

printf ("non-option ARGV-elements: ");

while (optind < argc)

{

printf ("%s ", argv[optind++]);

}

putchar ('\n');

}

}

I assume this only happens when argv[1] = NULL

Why assume? Add in code to check if this is happening.

Good point. I have checked and argv[1] = NULL.
 
M

Martin Ambuhl

Matt said:
The relevant part of my code reads as follows:

for ( i = 0 ; i < argc ; i++ )

{

printf("\narg = %d\n" , argc );

printf("\nCommand line arguement %d: %s. \n", i , *argv );

and the stdio.h header is loaded at the start. You may notice I have
added a * before the argv as I realised I wished to print the value
the pointer points at, was this a correct thing to do?


Almost certainly not. Check the following code. It may contain clues
to the solution to your problem. Or not. It's hard to tell from your
statement what it is you really want.

#include <stdio.h>

int main(int argc, char *argv[])
{
size_t i;
printf("arg = %d\n", argc);
for (i = 0; i < (size_t) argc; i++) {
if (argv)
printf("Command line argument %zu @ %p = \"%s\".\n", i,
(void *) argv, argv);
else
printf("Command line argument %zu @ %p (null pointer).\n", i,
(void *) argv);
}
return 0;
}


$a foo bar lisp green
arg = 5
Command line argument 0 @ 939d0 = "./a.exe".
Command line argument 1 @ 93a00 = "foo".
Command line argument 2 @ 93a30 = "bar".
Command line argument 3 @ 93a60 = "lisp".
Command line argument 4 @ 93a90 = "green".
Something else that is rather worrying is that if I comment this bit
out, later in the programme when it tries to read argv[1], I get
another segmentation fault. I assume this only happens when argv[1] =
NULL, but since I am almost certain the programme to supplied with at
least one argument, and that the error occurs when I try to print
argv[0] (which is the one thing that cannot be NULL!), something else
must be wrong here.

Something is wrong, but unless our crystal balls produce your code, no
one can even guess what errors you have made.
 
B

Ben Bacarisse

Matt said:
The programme in its entirity is far too large I'm afraid.

But you will probably solve the problems your self as you try to cut
it down to a minimal test case that fails. You will either find the
error or remain baffled with a small test program you *can* post.
Basically
the bit of troublesome code arises from my implementation of the
getopt_long function from the GNU library:

http://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Options.html#Getopt-Long-Options

with the example code:

http://www.gnu.org/software/libc/ma...ption-Example.html#Getopt-Long-Option-Example

My implemtation is as follows:

for ( i = 0 ; i < argc ; i++ )

{

printf("\nargc = %d\n" , argc );

printf("\nCommand line arguement %d: %s. \n", i , argv );

while (1)

{

static struct option long_options[] =

{

// These options set a flag.
{"stack" , no_argument , &stack_mode , 1}, // Enable
stack (convolution) mode

// These options don't set a flag. We distinguish them
by their indices.
{"configfile" , required_argument , 0 , 'c'},
{0 , 0 , 0 , 0}

};

// getopt_long stores the option index here.
int option_index = 0;

*getopt_val = getopt_long (argc, argv, "c:", long_options,
&option_index);


This looks very suspicious but how can we tell? What is getopt_val?
It it really a pointer to int, and does it point to a modifiable int
object? At the very least we'd need the declaration and the code that
might affect it's value from declaration to this point.

Post a small test program. Making one will teach you far more than
all the replies you might get here put together.
 
M

Matt

Post a small test program. Making one will teach you far more than
all the replies you might get here put together.

I'll give that a go.

In the meantime, DDD now reports that with my present code, the
segmentation fault occurs when I call the getopt_long function in the
above code:

"*getopt_val = getopt_long (argc, argv, "c:", long_options,
&option_index);"

Is this another example of where I shouldn't have used a *?

Kind Regards,

Matt
 
M

Matt

Having made a test programme as follows:

"// A programme to test argc and argv

// Load function libraries

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

// Main function

int main(int argc , char **argv)

{

int i; // DO loop index

// Print out argc and argv to screen

for ( i = 0 ; i < argc ; i++ )

{

printf("argc = %d\n",argc);
printf("argv[0] = %s\n",argv[0]);

}

}"

I had no errors, so calling the functions themselves doesn't seem the
be the problem.

I have since gone and commented out the getopt_long code I had added
and reintroduced the original code I had to read in the arguments:

" for ( i = 0 ; i < argc ; i++ ) // argc is the number of commmand
line arguements passed to the programme.

{

// Compare first two characters from command line arguement. If
they match, return 0 and execute statement.
if (!( strncmp( argv , "-c" , 2 )))

{

sprintf( config_file , "%s" , argv[ i+1 ] ); // Point programme
to a new config file by changing the
// config_file string to the argument following "-c".

}"

Interestingly, the programme now works flawlessly as it did before,
which clearly indicates the code I posted earlier for the getopt_long
code is the cause of my errors. I will endeavour to produce another
test programme to try and replicate the segmentation fault and post
back later.

Thanks for all the excellent responses so far.

Kind Regards,

Matt
 
M

Matt

I have just tried running the code given from the GNU Example page,
and as I should have expected, the code was fine.

Now when I put my own implementation of this code (which is of course
very similar) by itself, I got a segmentation fault whenever I put in
an argument such as "-c" or "-stack" that the programme is meant to
recognise and act upon. The problem does not occur if I use "c" or
"stack":

// A programme to test my implementation of the getopt_long function
in an independant environment from the main programme

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

static int stack_mode = 0;

int main( int argc , char *argv[] )

{

extern int stack_mode;

char *getopt_val;
int i;

opterr = 0;

printf("argc = %d\n",argc);

for ( i = 0 ; i < argc ; i++ )

{

printf("argv[%d] = %s\n",i,argv);

}

for ( i = 0 ; i < argc ; i++ ) // argc is the number of command line
arguments passed to the programme.

{

while (1)

{

static struct option long_options[] =

{

// These options set a flag.
{"stack" , no_argument , &stack_mode , 1}, // Enable stack
(convolution) mode

// These options don't set a flag. We distinguish them
by their indices.
{"configfile" , required_argument , 0 , 'c'},
{0 , 0 , 0 , 0}

};

// getopt_long stores the option index here.
int option_index = 0;

getopt_val = getopt_long (argc, argv, "c:", long_options,
&option_index);

// Detect the end of the options.
if (getopt_val == -1)

{

break;

}

switch (*getopt_val)

{

case 0:
/* If this option set a flag, do nothing else now. */
if ( long_options[option_index].flag != 0)

{

break;

}

printf ("option %s", long_options[option_index].name);

if (optarg)

{

printf (" with arg %s", optarg);

}

printf ("\n");
break;

case 'c':
printf ("option -c with value `%s'\n", optarg);
break;

case '?':
/* getopt_long already printed an error message. */
break;

default:
abort ();

}

}

/* Print any remaining command line arguments (not options). */
if (optind < argc)

{

printf ("non-option ARGV-elements: ");

while (optind < argc)

{

printf ("%s ", argv[optind++]);

}

putchar ('\n');

}

}

}

I have tried replacing "case 'c':" with "case '-c':" and so forth in
the case statements starting on line 92, but the source code would not
compile.

Kind Regards,

Matt
 
B

Ben Bacarisse

Matt said:
I'll give that a go.

In the meantime, DDD now reports that with my present code, the
segmentation fault occurs when I call the getopt_long function in the
above code:

"*getopt_val = getopt_long (argc, argv, "c:", long_options,
&option_index);"

Is this another example of where I shouldn't have used a *?

How could anyone tell? At the very least, show us the variable's
declaration and everywhere it is set.

You can't learn to program in C by added and removing * to see what
works. One you program will work and you will be happy. Lots of
programs "work" (i.e. behave as expected), with certain test cases
compiled with a particular compiler, on one particular system.
 
B

Ben Bacarisse

Matt said:
I have just tried running the code given from the GNU Example page,
and as I should have expected, the code was fine.

Now when I put my own implementation of this code (which is of course
very similar) by itself, I got a segmentation fault whenever I put in
an argument such as "-c" or "-stack" that the programme is meant to
recognise and act upon. The problem does not occur if I use "c" or
"stack":

Excellent -- a program we can read from top to bottom.
char *getopt_val; ....
getopt_val = getopt_long (argc, argv, "c:", long_options,
&option_index);

A problem. getopt_long (OK not topical, but the error is) returns an
it. getopt_val should be a "int" not a "char *".
switch (*getopt_val)

Boom! getopt_val does not point to an object so * of it causes
undefined behaviour.

Look at the declarations for any functions you use, and (by and large)
you will save any results returned in variables of that type.
 
K

Keith Thompson

Matt said:
// Print out argc and argv to screen

for ( i = 0 ; i < argc ; i++ )

{

printf("argc = %d\n",argc);
printf("argv[0] = %s\n",argv[0]);

}
[...]

The value of argc is a single number that doesn't change; why do you
print it inside the loop?

On each iteration of the loop, you print the value of argv[0]. You
almost certainly want to print argv.

Take a look at this. It's not intended to solve your problem, just to
demonstrate how to deal with argc and argv. Checking each argument
against NULL is perhaps overkill, but it's better to be too cautious
than not cautious enough.

#include <stdio.h>
int main(int argc, char **argv)
{
int i;
printf("argc = %d\n", argc);
for (i = 0; i < argc; i ++) {
if (argv == NULL) {
printf("argv[%d] = NULL\n", i);
}
else {
printf("argv[%d] = \"%s\"\n", i, argv);
}
}
return 0;
}

Also, please don't use "//" comments when posting to Usenet. They're
not supported in C90 (though many compilers support them as an
optional extension), and they can cause problems with line wrapping.
If Usenet software somewhere splits a "//" comment across two lines,
it creates a syntax error. If a "/* ... */" comment is split, it's
generally not a problem. And keep your lines short, no more than 72
columns.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top