Создайте модифицируемый строковый литерал в C++

Действительно ли возможно создать модифицируемый строковый литерал в C++? Например:

char* foo[] = {
    "foo",
    "foo"
};
char* afoo = foo[0];
afoo[2] = 'g'; // access violation

Это производит нарушение прав доступа, потому что "нечто" s выделяются в постоянной памяти (.rdata раздел, которому я верю). Там какой-либо путь состоит в том, чтобы вызвать "нечто" s в перезаписываемую память (.data раздел)? Даже через прагму было бы приемлемо! (Компилятор Visual Studio)

Я знаю, что могу сделать strdup и много других вещей обойти проблему, но я хочу знать конкретно, если я могу сделать, как я попросил.:)

5
задан Anne 16 June 2010 в 16:23
поделиться

6 ответов

Вы можете создать многомерный массив символов:

#include <iostream>

int main(int argc, char** argv)
{
    char foo[][4] = {
        "foo",
        "bar"
    };
    char* afoo = foo[0];
    afoo[2] = 'g';
    std::cout << afoo << std::endl;
}

Более подробный способ определения массива:

char foo[][4] = {
    {'f', 'o', 'o', '\0'},
    {'b', 'a', 'r', '\0'}
};
1
ответ дан 18 December 2019 в 11:53
поделиться

Поскольку это C ++, "лучшим" ответом было бы использование строкового класса ( std :: string , QString , CString и т. Д. В зависимости от вашей среды).

Чтобы ответить прямо на ваш вопрос, вы не должны изменять строковые литералы. Стандарт говорит, что это неопределенное поведение. Вам действительно нужно так или иначе продублировать строку, иначе вы напишете неверный C ++.

9
ответ дан 18 December 2019 в 11:53
поделиться

Я бы не стал этого делать. Поэтому я могу предложить только неприятный уродливый прием, который вы могли бы попробовать: Получите страницу, на которой находится ваш постоянный литерал, и снимите защиту с этой страницы. См. Функцию VirtualProtect () для Win32. Однако даже если это сработает, это не гарантирует постоянного поведения. Лучше не делай этого.

1
ответ дан 18 December 2019 в 11:53
поделиться

Я думаю, что самое лучшее, что вы можете сделать, это инициализировать простой char [] (не char * []) ​​литералом:

char foo[] = "foo";

Это Однако в какой-то момент я все равно сделаю копию.

Единственный способ обойти это - использовать вызовы системного уровня, чтобы пометить страницу, на которой находится строковый литерал, как доступную для записи. В этот момент вы действительно говорите не о C или C ++, вы действительно говорите о Windows (или любой другой системе, в которой вы работаете). Вероятно, это возможно в большинстве систем (если данные действительно не находятся в ПЗУ, что может иметь место, например, во встроенной системе), но я точно не знаю подробностей.

Да, и не забывайте, что в вашем примере:

char* foo[] = {
    "foo",
    "foo"
};

Поскольку стандарт (C99 6.4.5/6 «Строковые литералы») говорит:

Не указано, являются ли эти массивы различными, если их элементы имеют соответствующие значения.

Нет уверенности в том, будут ли 2 указателя в этом массиве указывать на один и тот же или разные объекты. Почти все компиляторы будут иметь эти указатели, указывающие на один и тот же объект по одному и тому же адресу, но это не обязательно, и в некоторых более сложных ситуациях указателей на строковые литералы компилятор может выдавать две отдельные идентичные строки.

У вас может быть даже сценарий, в котором один строковый литерал существует «внутри» другого:

char* p1 = "some string";
char* p2 = "string";

p2 вполне может указывать на конец строки, на которую указывает p1 .

Таким образом, если вы начнете изменять строковые литералы с помощью какого-либо хака, который вы можете выполнить в системе, вы можете случайно изменить некоторые «другие» строки. Это одна из вещей, которые может принести неопределенное поведение.

5
ответ дан 18 December 2019 в 11:53
поделиться

Если вы храните строку в массиве, вы можете ее изменить.

Не существует способа "корректной" записи в память, доступную только для чтения.

Можно, конечно, перестать использовать C-строки.

2
ответ дан 18 December 2019 в 11:53
поделиться

Да.

   (char[]){"foo"}
-3
ответ дан 18 December 2019 в 11:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: