Why doesn't this loop work like it should?

Nov 18, 2013 at 11:07pm
Basically I know how to put my strings and change them into chars for a program I am writing, but when I try to make a loop that does the same thing, the loop changes the values of each element in the array to the same thing, why???

1
2
3
4
5
6
7
8
9
10
11
12
13
 const char* MAD[10];
	string f;
	for (int x = 0; x < 3; x++) {
		
		cin >> f;
		MAD[x] = f.c_str();
	}
//THIS SHOULD WORK LIKE THIS:
const char* MAD[10]
string f = "hello";
string d = "goodbye";
MAD[0] = f.c_str();
MAD[1] = d.c_str();
Nov 18, 2013 at 11:12pm
please anyone help?
Nov 18, 2013 at 11:21pm
const char* <- this is not a string. This is a pointer.

a std::string contains a buffer which holds the actual string data. When you do MAD[x] = f.c_str(); what you're doing is making MAD[x] point to the data contained in the 'f' string.

When you change 'f' to contain some other data... the data MAD[x] points to changed.

Here's a simpler example of what's going on:

1
2
3
4
5
6
7
8
9
10
int var = 5;  // <- this variable actually contains the 5

int* ptr = &var;  // <- this pointer points to 'var'

cout << *ptr;  // prints 5 as you'd expect

var = 10;

cout << *ptr;  // now this prints 10.  'ptr' still points to 'var'... but 'var' has
  // changed to be 10. 


What you're doing is the same thing:
1
2
3
4
5
6
7
8
9
std::string s = "something"; // <- 's' actually contains the string data

const char* ptr = s.c_str(); // <- 'ptr' DOES NOT contain the string data, it just
   // points to 's's string data

s = "foobar"; // <- s's string data changed

cout << ptr; // <- the data 'ptr' pointed to changed... so this probably won't
   // print "something" any more. 




If you want to convert the string to a series of chars... you will need to allocate an actual buffer to contain the string data (ie: you'll need an ARRAY of chars... not just a pointer).

You can use a function like strcpy to copy the string data over:

1
2
3
4
5
6
7
char buffer[20];  // <- an array of 20 chars
std::string foo = "blarg";

strcpy( buffer, foo.c_str() ); // actually copies the string data into 'buffer'

foo = "woopwooop";
cout << buffer;  // <- prints "blarg" 


please anyone help?


Give us more than 5 mins to respond.
Nov 18, 2013 at 11:27pm
The pointer returned may be invalidated by further calls to other member functions that modify the object.

In your case the string f has reused its internal array and thus you have got the same address every time.

You were just lucky. Don't store pointers to internal arrays that may get deleted on the whim of a string.
Nov 20, 2013 at 5:35am
can anyone else please help me on this matter? strcpy doesnt not work for const char*, only char*.
Nov 20, 2013 at 5:39am
closed account (S6k9GNh0)
http://www.cplusplus.com/reference/cstring/strcpy/

Or the more in-depth open-group specification: http://pubs.opengroup.org/onlinepubs/009695399/functions/strcpy.html
Nov 20, 2013 at 5:46am
I have read both of those but I still don't understand how to make strcpy work when it is a const char* and not a char*. is the only possible solution to convert the const char* to a char* for the time being then to switch it back after?
Nov 20, 2013 at 6:03am
strcpy doesnt not work for const char*, only char*.


You should not be copying to a const char*. You should be copying to an array of chars. Remember that a const char* is a pointer. Pointers merely contain an address... they do not contain string data.

Therefore you cannot copy string data to a pointer. This is the conceptual problem you seem to be misunderstanding.

You need a buffer (an array) of characters. You then copy the string data to that buffer.

My previous example, reposted:

1
2
3
4
char buffer[20];  // <- an array of 20 chars
std::string foo = "blarg";

strcpy( buffer, foo.c_str() ); // actually copies the string data into 'buffer' 


Again note that 'buffer' is an array and not a pointer. It's also not const because we need to modify it.


That said... you can use a pointer... but only if that pointer points to a buffer.
Last edited on Nov 20, 2013 at 6:04am
Nov 20, 2013 at 6:08am
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <string>
#include <memory>
#include <cstring>

// convert string to c-style string, alocate space for 'extra' chars
// release the allocated memoty with delete[]
char* string_to_cstr( const std::string& str, std::size_t extra = 0 )
{
    char* cstr = new char[ str.size() + 1 + extra ] ;

    std::uninitialized_copy( str.begin(), str.end(), cstr ) ; // copy chars
    cstr[ str.size() ] = 0 ; // null terminate

    return cstr ;
}

int main()
{
    std::string abcd = "abcd", efg = "efg" ;

    char* mad[] = { string_to_cstr(abcd,50), string_to_cstr(efg,25),
                     string_to_cstr("ijklmnop"), string_to_cstr("qr",10) } ;

    for( char* cstr : mad ) std::cout << cstr << '\n' ;
    std::cout << '\n' ;

    std::strcpy( mad[0], "bigger string (max 54 chars)" ) ;
    std::strcpy( mad[1], "hello" ) ;
    std::strcpy( mad[2], "world" ) ;
    std::strcpy( mad[3], "bye" ) ;
    for( char* cstr : mad ) std::cout << cstr << '\n' ;

    for( char*& cstr : mad ) { delete[] cstr ; cstr = nullptr ; }
}
abcd
efg
ijklmnop
qr

bigger string (max 24 chars)
hello
world
bye
Last edited on Nov 20, 2013 at 6:11am
Nov 20, 2013 at 6:10am
Do you mean:
1
2
3
4
std::vector<const std::string> MAD;

std::string f;
if ( std::cin >> f ) MAD.push_back( f );
Topic archived. No new replies allowed.