format specifies type 'char *' but the arg

2020-08-09 05:15发布

问题:

I am attempting to check and output the command line arguments given for a specific program "format.c" when called from the terminal. I am getting the following error and I do not understand what it is telling me. error: format specifies type 'char *' but the argument has type 'char' [-Wformat] here is my code thus far:

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

int printArguments( int argc, char **argv )
{
    int i;
    printf( "Total number of arguments: %d", argc );
    for( i = 0; i <= argc; i++ ){
        printf( "argv[%d] = %s\n", i, *argv[i] );
    }
    return 0;
}

int main ( int argc, char **argv )
{
    if( argc != 3 ){
        puts( "You failed to enter the correct number of arguments." );
        printf( "You entered: \nargv[0] = %s\nargv[1] = %s\nargv[2] = %s\n",
               argv[0], argv[1], argv[2] );
        puts( "Argument format should be, \"./format (arg1 = int value)"
             "(arg2 = file name)\"\n" );
        return 0;
    }
    if( atoi(argv[1]) < 25 ){
        printf( "\nargv[1] = %d\nYou entered a value too small for the format\n",
        atoi(argv[1]) );
        return 0;
    }
    if( atoi(argv[1]) > 100 ){
        printf( "\nargv[1] = %d\nYou entered a value too large for the           format\n",
        atoi(argv[1]) );
        return 0;
    }

    printArguments( argc, **argv );

    return 0;
} /*end of main */

回答1:

Try

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

int printArguments( int argc, char **argv )
{
    int i;
    printf( "Total number of arguments: %d", argc );
    for( i = 0; i <= argc; i++ ){
        printf( "argv[%d] = %s\n", i, *(argv+i) );
    }
    return 0;
}

int main ( int argc, char **argv )
{
    if( argc != 3 ){
        puts( "You failed to enter the correct number of arguments." );
        printf( "You entered: \nargv[0] = %s\nargv[1] = %s\nargv[2] = %s\n",
               argv[0], argv[1], argv[2] );
        puts( "Argument format should be, \"./format (arg1 = int value)"
             "(arg2 = file name)\"\n" );
        return 0;
    }
    if( atoi(argv[1]) < 25 ){
        printf( "\nargv[1] = %d\nYou entered a value too small for the format\n",
        atoi(argv[1]) );
        return 0;
    }
    if( atoi(argv[1]) > 100 ){
        printf( "\nargv[1] = %d\nYou entered a value too large for the           format\n",
        atoi(argv[1]) );
        return 0;
    }

    printArguments( argc, argv );

    return 0;
} /*end of main */

Corrections are: printArguments( argc, argv ); and printf( "argv[%d] = %s\n", i, *(argv+i) );

[EDITED] printArguments function expects arguments of type int and char **. That is what argc and argv already are. If you type **argv, you are dereferencing pointer twice. So, you are doing char ** => char * => char (this is what dereferencing does, "removes" one star). So, function expects pointer to a pointer to a char, but it gets a char. Wrong.

Secondly, to explain the mistake with *argv[i], one has to understand how C programmer stores its data. Firstly, C program is given some internal memory that is divided in four segments: stack segment, data segment, heap segment and code segment. Data segments stores global variables, code segment stores program's code. Heap segment stores dynamically allocated variables. They do not have their names, and one retrieves data by it's address in memory. This is done with argv[i] i.e. *(argv+i). This is exactly the same thing, just another syntax.

So, let's overview how certain data structures are stored in memory: 1. int a[5] is an array of 5 integers. If not global array, it is stored on stack. With this declaration, 20 Bytes are occupied in memory. We can save up to 5 integers in this array or less, but not more. 2. int *p = NULL is a pointer. It can point to an integer. With this initialization, it points nowhere. When we say that variable "points" at somewhere, we mean that it does not contain an exact data (number, character) but an address where this data is. 3. int *p = (int *) malloc (sizeof(int) * 5) is a variable that points at the first of five integers, i.e. it contains an address in the heap segment of the array of five integers. So, *p <=> *(p+0) <=> p[0]. You can visualize this by moving pointers around inside the array. So, p has the address of the first one. We retrieve others using some "pointers arithmetic".

4. int a[3][5] is a statically allocated two dimensional array. It is an array which elements are also arrays. Since it is not dynamically allocated, it is stored on stack or data segment (depending on where it is declared, inside or outside of some function). 5. int *a[5] is an array of pointers. So, firstly there is a statically allocated array (stack/data segment). Afterwards, we can dynamically allocate member arrays (but they will be on heap). 6. int **a is a pointer to a pointer. So, a contains an address of a place that also has an address where some integer is stored. So, a points to a place that also points to a place with the integer. After step b) we said it should point to first of the five integers in the array (of course, in heap). What are members of this array? We said that a points to something that also points to something, so members are also pointers. We can say where these pointers point now. This is done after step c).

Finally, with chars we have the same situation as with integers. 7. is like case 1 (but you can see that we save one extra Byte for '\0') 8. is like case 5 Case with char ** would be like case 6.

And the (*) case is how your int argc and char **argv look like. These are arguments to the main() function, and are therefore stored in the stack frame for it. argv is pointer that points to the first of the elements that are also pointers, pointing to fist character in arrays of characters[it would be wrong to say that argv is 'array of arrays of chars', that would be true if we had char argv[50][50]; it would be wrong to say that argv is an array of pointers, that would be char *argv[50]). So, argv is pointer that points to the first of n pointers that point to first chars.

So, finally, argv[i] <=> *(argv+i) [this is how we retrieve ith pointer] That means *argv[i] <=> *(*(argv+i)) [this is how we retrieve where the ith pointer points at. It points at the first character of the ith argument!]

So, argv[i] is of type char *, and *argv[i] is of type char. You have tried to print argument with %s i.e. printf() expects "string" i.e. "array of chars" i.e. THE ADDRESS of the first char in a sequence of chars (which is what arrays in C actually store) and not just an actuall char.

I hope this helps. :)



回答2:

You should be passing argv[i] not *argv[i] to printf in printArguments, as the type of argv is char **. So argv[i] is of type char * and *argv[i] is of type char. The %s specifier to printf expects a char * argument.

You should also be passing argv as the argument to printArguments, not **argv for the same reasons. You want to pass the entire list of arguments, not a pointer to the first character of the first argument. I'm surprised you're not getting a warning for that as well.