3

Let's say you have a string like this:

char* a="01234"

Letting &a=0000, &(a+1)=0001, &(a+2)=0002, and so on, what happens if there is some memory already allocated for another variable at 0007, and you try resizing a to a larger size (a="0123456789")? Will a move to a new location that can fit the larger string, or will the data in 0007 be overwritten?

Edit:

I don't understand what people mean when they say resizing C-style strings is not allowed.

char* a="01234"
cout << &a; //Prints 00FF1360
cout << a;  //Prints 01234
a="0123456789"
cout << &a; //Still prints 00FF1360
cout << a; //Prints "0123456789"

The pointer a didn't change at all when I reassigned it. It seems like the original string "01234" was just destroyed and "0123456789" replaced it in the same location.

Nevermind, I was printing the location of the pointer rather than the location it was pointing to. As a side question, does anyone know how to print a character pointer's value without it printing the string instead?

john smith
  • 619
  • 1
  • 9
  • 15
  • 14
    These are C-style strings. If you're really using C++, use std::string instead wherever you can. – Joe Aug 08 '11 at 20:25
  • How do you plan to resize? Do you want to realloc? – evnu Aug 08 '11 at 20:26
  • 1
    Use `std::string` it is safer and expands memory as necessary. – Thomas Matthews Aug 08 '11 at 20:27
  • 3
    `a="0123456789"` will not resize anything. I highly recommend grabbing a [good introductory C++ book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – R. Martinho Fernandes Aug 08 '11 at 20:27
  • 3
    In your edit, you are printing `&a`, which is the *address* of the *pointer* to the character. The address of the pointer doesn't change, but the *value* of the pointer does. Try: `printf("%p\n", a);` to print the value of the pointer (that particular output is easier to get with C stdio than with C++ iostreams). – Greg Hewgill Aug 08 '11 at 20:43
  • @Joe: using `std::string` wherever you can sounds just terrible... –  Aug 08 '11 at 20:48
  • 1
    @Vlad: It's more or less true. Use c++ constructs if you're writing C++. If you need to interface with C code, handle those cases. But why would you choose to do C-style strings if you didn't have to? – Joe Aug 08 '11 at 20:50
  • 1
    @albert: To print a pointer, try `std::cout << (void*)p << "\n";` or `std::printf("%p\n", p);`. – Robᵩ Aug 08 '11 at 20:55
  • @Joe: Just because I don't need a dynamically allocated string and want to work with array of characters or string literals, which are also C++. If you don't know the difference, or what `std::string` does, I guess you have to learn about those first, and then decide what is applicable in your case, rather than following an arguable rule to use `std::string` wherever possible. –  Aug 08 '11 at 20:59

7 Answers7

5

c-style strings like that are just arrays. Arrays allocated via malloc can be resized using realloc, but those assigned like that aren't. Accessing memory outside the string is accessing memory that could be used by something else, or is uninitialized, or otherwise bad.

Herms
  • 37,540
  • 12
  • 78
  • 101
4

There is no resizing if you reassign a to something else; they are pointers to different memory locations. (And in the case of constant strings like the above, they are immutable read-only strings.)

Joe
  • 41,484
  • 20
  • 104
  • 125
4

What you've written isn't C++, and it's definitely not allowed.

Correct way:

const char * a = "01234";  // pointer to array of six const chars.
char b[] = "01234";        // array of six chars

You can only read the values a[0] to a[5], but never change them. You can change the values b[i] for i in 0 to 5, but be sure not to set b[5] to anything but zero.

Any access, read or write, to a[i] or b[i] with i greater than five is undefined behaviour and almost definitely suicidal.

In the case of a, the string literal usually lives in a global, read-only part of memory. On the other hand, b is just an automatic array in the local scope that's initialized to the given six characters (including terminal zero).

Conversely, if by some mysterious ways you have already come at the address of some valid area of memory, you could wreak all sorts of havoc:

char * evil = use_dastardly_exploit();
memcpy(evil, my_leet_shellcode, 1024);

Indeed C and C++ let you freely roam about your process's virtual memory space, but you may get shot at any point!

(For you second question, writing a = "56789"; is fine, but it will set a to point to a different string and not modify the original one (and a should still be of type const char *).)

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • It *is* C++, it just happens to be part that's inherited from C :) – Ken Wayne VanderLinde Aug 08 '11 at 20:28
  • 1
    @albert einstein: No one said that **undefined behaviour** means it doesn't work. You can read about it in [this question](http://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior). – R. Martinho Fernandes Aug 08 '11 at 20:29
  • 2
    @Ken: It's definitely the legacy part of C++ which is deprecated and will issue a warning, and I would be remiss to suggest that it was OK to refer to a string literal by a pointer to non-const. :-) – Kerrek SB Aug 08 '11 at 20:31
0

It will be overwritten. Use std::string if you need dynamic length strings.

young
  • 2,163
  • 12
  • 19
0

Under most circumstances the question should not be "Are C-Like Strings dangerous ?". The question should be "What are the reasons for not using stl strings" (std::string).

There is also a pretty similar discussion here: Is the function strcpy always dangerous?

Community
  • 1
  • 1
fyr
  • 20,227
  • 7
  • 37
  • 53
0

You have to resize the array a points to if you want it to contain more chars. Assigning a larger string won't automatically resize the underlying array (instead it would overwrite other variables or memory not belonging to the program at all). But if you do resize the array (using realloc for example) it may move the array to a new memory location.

stewe
  • 41,820
  • 13
  • 79
  • 75
0

@albert, maybe this program will help you understand what is going on.

#include <iostream>

int main() {

  // Create an anonymous array of 6 bytes *somewhere* and
  //   point "a" at the first byte.
  const char *a = "01234";

  // Display the string:
  std::cout << a << "\n";

  // Display that value of the pointer
  std::cout << (const void*)a << "\n";

  // Create an anonymous array of 8 bytes somewhere else and
  //   point "a" at the first byte.
  a = "0123456";
  std::cout << a << "\n";
  std::cout << (const void*)a << "\n";

  // Note well: only the pointer changed. Neither anonymous array changed.

  // Create an array of 4 bytes named "b"
  char b[] = "012";
  // point a at it:
  a = b;
  std::cout << a << "\n";
  std::cout << (const void*)a << "\n";
  std::cout << (void*)b << "\n";
}
Robᵩ
  • 163,533
  • 20
  • 239
  • 308