1

I am trying to convert a char stored in the argv array to int, using the atoi function, I am new to C++ and passing arguments, so please bear with me.

Every time I attempt to set the value stored at atoi[1] to a const char, and print the char, it doesn't print anything at all. If I am doing this wrong it should still print a memory address, right?

I am setting it to a const char because the atoi function needs a const char as it's argument. (Please correct me if I am wrong)

I have been doing this via ideone.com, so my argv array isn't really set at runtime, since ideone doesn't allow that.

Here is my code so far:

#include <iostream>
#include<string>
#include <stdlib.h>
using namespace std;

int main() {
    int argc;
    char *argv[4]; 

    *argv[0] = 'x';
    *argv[1] = '5';//this will be the length of our first array for testing
    *argv[2] = '3';//this will be the length of our second array for testing
    *argv[3] = '4';//this will be the length of our third array for testing
    argc = 4;

    const char  * argv1 = argv[1];

    cout << "*argv[1]: " <<  *argv[1] << endl;
    cout << "argv[1]: " <<  argv[1] << endl;
    cout << *argv1;

    //int x = atoi(argv1);

    return 0;
}

UPDATED CODE: Now featuring the ability to compile!

#include <iostream>
#include <string>
#include <stdlib.h>

using namespace std;

int main() {
    char nullGuy = NULL;
    char * nullptr1 = &nullGuy;//Null ptr

    int argc;
    const char * argv[5]; 

    argv[0] = "x";
    argv[1] = "5";
    argv[2] = "3";
    argv[3] = "4";
    argv[4] = nullptr1;

    argc = 4;

    int x = atoi(argv[1]);

    cout << "argv[1]: " <<  argv[1] << endl;
    cout << "x: " << x << endl;

    return 0;
}
  • possible duplicate of [Convert c++ argument to int](http://stackoverflow.com/questions/2797813/convert-c-argument-to-int) – hlscalon Nov 14 '14 at 12:32

3 Answers3

1

None of your pointers point to valid memory. You're getting undefined behavior when you deference them. Even if this weren't true, you're not null-terminating them, so they're not strings.

Change to:

#include <iostream>
#include <string>
#include <stdlib.h>

using namespace std;

int main() {
    int argc;
    const char * argv[5]; 

    argv[0] = "x";
    argv[1] = "5";
    argv[2] = "3";
    argv[3] = "4";
    argv[4] = nullptr;
    argc = 4;

    int x = atoi(argv[1]);

    cout << "argv[1]: " <<  argv[1] << endl;
    cout << "x: " << x << endl;

    return 0;
}

As explanation, this from your original code:

*argv[0] = 'x';

is the same as:

*(argv[0]) = 'x';

which is the same as:

argv[0][0] = 'x';

which means "take the address stored at argv[0], and store the value 'x' there". Since you never initialize argv[0], or any of your argv members, none of these addresses are valid, and they are highly unlikely to point to any memory that you're allowed to write to.

If you'd declared argv as, say, char argv[4][20];, then this would be OK, since argv[0] is no longer an uninitialized pointer, but an array of 20 characters which you can write to.

However, even if you did that, you'd want to do something like:

argv[1][0] = 'x';
argv[1][1] = '\0';

because the thing you pass to atoi() must be an actual (C-style) string, not a pointer to a single character, and strings must be terminated with the null character.

Instead, in the code I gave:

const char * argv[5];
argv[1] = "5";  //  <-- Note use of double, not single, quotes

does make argv[1] a pointer to char, but points it to the string literal "5", which is null-terminated, is a C-style string, and is suitable for passing to functions like atoi(). You will not be able to modify that string, however, so if you want to do that, you'll need to either declare an actual array, or dynamically allocate some memory with the new operator.

You can also change nullptr to NULL if, as the comment to another answer suggests, you're not using C++11. I added that fifth member of argv set to nullptr because when you do start using actual command lines rather than manually setting it up, the argv that gets passed to main() is going to have that member.

Crowman
  • 25,242
  • 5
  • 48
  • 56
  • Thanks this helps tremendously. –  Nov 14 '14 at 12:57
  • So, when I actually pass arguments via command line, the last argument in my argv array will be a null ptr, which is a pointer to NULL, correct? --and yes, I am compiling for g++ and currenlty it is not using C++11. –  Nov 14 '14 at 14:48
  • Thank you, that's very intersting. So argv is similar in sense to a c-string, since it is an array of char arrays that is terminated by a pointer to a null value. So argv is always 2D? I thought that a 2D array was declared like so **arrayName. Also really sorry if I butchered that...I'm really trying to wrap my head around argv. –  Nov 14 '14 at 14:54
  • Things can get a bit slippery when you start getting into the technical differences between pointers and arrays in this context. Technically `argv` is a single pointer to `char *`, and not an array at all, but for most practical purposes you can treat it as if it were a single-dimensional array of `char *` with `argc + 1` elements, the last of which will always be `NULL`. In the sense that its last usable element functions as a sentinel value to signal "end of", it's similar to a C string, yes. – Crowman Nov 14 '14 at 15:02
  • Because each element of `argv` points to a C string which can *also* be treated, for most practical purposes, as a single-dimensional array (of `char`, though, not of `char *`) this allows you to do things like `argv[1][3]`, making `argv` *look* as though it's a two-dimensional array, but it's actually not. `argv[1][3] = 'x';` is basically equivalent to `char * str = argv[1]; str[3] = 'x';` – Crowman Nov 14 '14 at 15:09
  • so if I want to use atoi() on a single element of argv, I always have to add a null terminator, since atoi only works on c-strings. I see now. –  Nov 14 '14 at 15:10
  • You're correct in that `atoi()` always needs to be sent a C string, but the `argv` that `main()` receives contains elements that always point to null-terminated C strings, or to `NULL`. So `x = atoi(argv[1]);`, (presuming here that `argc > 2`) and similar will be fine, without you having to do anything about manually adding terminating null characters. But if you're creating `argv` yourself, you need to take steps to make sure the elements point to null-terminated C strings before passing them to `atoi()`. – Crowman Nov 14 '14 at 15:12
0

In general, to convert a std::string to an integral type, you can use std::stoi.
Your code shows undefined behaviors as you're writing to pointers which point to unallocated memory; use std::string [] or a standard container of std::strings.

edmz
  • 8,220
  • 2
  • 26
  • 45
0

The main ptoblem is that you did not allocate memory that would be pointed to by the elements of the array and where you are going to write characters.

The valid code could look the following way

#include <iostream>

int main() 
{
    const size_t N = 4;
    int argc;
    char *argv[N];

    argv[0] = new char( 'x' );
    argv[1] = new char( '5' );//this will be the length of our first array for testing
    argv[2] = new char( '3' );//this will be the length of our second array for testing
    argv[3] = new char( '4' );//this will be the length of our third array for testing
    argc = N;

    const char *argv1 = argv[1];

    std::cout << "*argv[1]: " << *argv[1] << std::endl;
    std::cout << "argv[1]: "  << ( void * )argv[1]  << std::endl;
    std::cout << *argv1 << std::endl;;

    for ( char *p : argv ) delete p;

    return 0;
}

The output can look like

*argv[1]: 5
argv[1]: 0x9aeb018
5

Take into account using casting to void * in statement

    std::cout << "argv[1]: "  << ( void * )argv[1]  << std::endl;

Otherwise argv1[1] will be interpretated by operator << as the first character of a string terminated by zero.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335