Изменение размера строк в C ++ опасно - PullRequest
3 голосов
/ 09 августа 2011

Допустим, у вас есть такая строка:

char* a="01234"

Обозначение & a = 0000, & (a + 1) = 0001, & (a + 2) = 0002 и т. Д., Что происходитесли на 0007 уже выделена какая-то память для другой переменной, и вы пытаетесь изменить размер a до большего размера (a = "0123456789")?Будет ли перемещение в новое место, которое может соответствовать большей строке, или данные в 0007 будут перезаписаны?

Редактировать:

Я не понимаю, какие людиЯ имею в виду, когда они говорят, что изменение размера строк в стиле C. не допускается.

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

Указатель a вообще не изменился, когда я переназначил его.Кажется, что исходная строка «01234» была просто уничтожена, и «0123456789» заменил ее в том же месте.

Не важно, я печатал местоположение указателя, а не местоположение, на которое он указывал,В качестве дополнительного вопроса, кто-нибудь знает, как напечатать значение символьного указателя, не печатая вместо него строку?

Ответы [ 7 ]

5 голосов
/ 09 августа 2011

такие строки в стиле c - это просто массивы. Размеры массивов, выделенных с помощью malloc, можно изменить с помощью realloc, но массивы, назначенные таким образом, - нет. Доступ к памяти вне строки - это доступ к памяти, которая может быть использована кем-то другим, или не инициализирована, или иным образом повреждена.

4 голосов
/ 09 августа 2011

То, что вы написали, не является C ++, и оно определенно не разрешено.

Правильный путь:

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

Вы можете только читать значения a[0] до a[5], но никогда не меняйте их.Вы можете изменить значения b[i] для i в диапазоне от 0 до 5, но не устанавливайте для b[5] значение, отличное от нуля.

Любой доступ, читайте или записать в a[i] или b[i] с i больше пяти равно неопределенное поведение и почти наверняка самоубийство.

В случае a строковый литералобычно живет в глобальной части памяти, доступной только для чтения.С другой стороны, b - это просто автоматический массив в локальной области видимости, который инициализируется указанными шестью символами (включая нулевой терминал).

И наоборот, если по каким-то таинственным причинам у вас есть уже по адресу какой-то действительной области памяти, вы можете нанести разного рода хаос:

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

Действительно, C и C ++ позволяют свободно перемещаться по виртуальной памяти вашего процесса, но вы можете получить выстрелв любой момент!

(Для вас второй вопрос - хорошо написать a = "56789";, но a будет указывать на другую строку, а не изменять исходную (а a все равно должно бытьтипа const char *).)

4 голосов
/ 09 августа 2011

Изменение размера невозможно, если вы переназначаете a на что-то другое;они являются указателями на разные области памяти.(А в случае константных строк, подобных описанным выше, они являются неизменяемыми строками только для чтения.)

0 голосов
/ 09 августа 2011

@ Альберт, возможно, эта программа поможет вам понять, что происходит.

#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";
}
0 голосов
/ 09 августа 2011

Вы должны изменить размер массива, на который указывает a, если вы хотите, чтобы он содержал больше символов. Присвоение большей строки не приведет к автоматическому изменению размера базового массива (вместо этого будут перезаписаны другие переменные или память, не принадлежащая программе вообще). Но если вы измените размер массива (например, с помощью realloc), он может переместить массив в новую область памяти.

0 голосов
/ 09 августа 2011

В большинстве случаев вопрос не должен быть"Are C-Like Strings dangerous ?".Вопрос должен звучать так: "What are the reasons for not using stl strings" (std :: string).

Здесь также довольно похожее обсуждение: Всегда ли опасна функция strcpy?

0 голосов
/ 09 августа 2011

Будет перезаписано. Используйте std::string, если вам нужны строки динамической длины.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...