Изменение строковых констант?

Возможный дубликат:
Почему я получаю ошибку сегментации при записи в строку?

Я хочу написать функцию, которая меняет данную строку, переданную в нее. Но я не могу. Если я doReverse функцию doReverse (см. Код ниже) с помощью массива символов, мой код работает хорошо.

Я не могу понять, почему это не работает. Я могу получить доступ к str[0] в doReverse , но я не могу изменить любое значение массива с помощью указателя char. Есть идеи?

 void doReverse(char *str) { str[0] = 'b'; } void main(void) { char *str = "abc"; doReverse(str); puts(str); } 

Обновить:

Я знаю, как писать обратную функцию, передавая ему массив символов:

 void reverse1(char p[]) { int i, temp, y; for (i = 0, y = strlen(p); i < y; ++i, --y) { temp = p[y-1]; p[y-1] = p[i]; p[i] = temp; } } 

Но, я хочу написать другую версию, которая получает указатель char в качестве параметра.

Простейшим решением является изменение объявления str на

 char str[] = "abc"; 

Это делает str массив символов, который инициализируется строкой «abc». В настоящее время у вас есть str как указатель-к-char, инициализированный, чтобы указать на строку, описываемую строковым литералом. Существует ключевое различие: строковые литералы доступны только для чтения, чтобы предоставить компилятору максимальную гибкость в отношении того, где их хранить; это UB, чтобы изменить их. Но массивы char изменяемы, и поэтому их можно модифицировать.

PS. main() возвращает int .

Поскольку вы учитесь на экзамене, я немного буду излагать свои комментарии, чтобы объяснить, что на самом деле происходит:

 char *str = "abc"; 

str – указатель, хранящийся в стеке. Он инициализируется, чтобы указать на буквальную строку "abc" . Эта буквальная строка будет храниться в разделе данных вашего скомпилированного исполняемого файла и загружается в память при загрузке вашей программы. Этот раздел памяти доступен только для чтения, поэтому при попытке изменить данные, на которые указывает str, вы получаете нарушение доступа.

 char* str = malloc(sizeof(char) * 4); strcpy(str, "abc"); 

Здесь str – это тот же самый указатель стека, что и первый пример. На этот раз инициализируется указание на 4-символьный блок памяти в куче, который вы можете читать и писать. Сначала этот блок памяти неинициализирован и может содержать что угодно. strcpy считывает блок постоянной памяти, где хранится «abc», и копирует его в блок памяти чтения и записи, на который указывает str. Обратите внимание, что установка str[3] = '\0' избыточна, поскольку strcpy делает это уже.

В стороне, если вы работаете в visual studio, вместо этого используйте strcpy_s, чтобы убедиться, что вы не перезаписываете свой буфер, если копируемая строка больше, чем вы ожидали.

 char str[] = "abc"; 

Здесь str теперь представляет собой массив, выделенный в стеке. Компилятор будет точно соответствовать строковому литералу, используемому для его инициализации (включая терминатор NULL). Память стека – это чтение-запись, поэтому вы можете изменять значения в массиве, как хотите.

 char str[4] = "abc"; 

Это фактически то же самое, что и предыдущая версия, только вы говорите компилятору, что знаете лучше, чем он делает, как долго должен быть массив. У вас могут возникнуть проблемы, если вы измените строку, а не размер массива.

Поскольку это домашнее задание, я дам совет, но я не опубликую полное решение.

Я предполагаю, что вы получаете нарушение доступа на str [0] = ‘b’? Это связано с тем, что «abc» является строковым литералом.

Скопируйте строковые str-точки перед вызовом reverse или обратитесь, чтобы выделить буфер и поместить в него переменную строку.

Имейте в виду, что вам придется освободить всю память, которую вы выделите.

Господи, Господи. Для всех, предлагающих способы осуществления обмена, внимательно прочитайте вопрос; нет ничего хуже, чем повторять уже совершенно четко сформулированный вопрос. Независимо от метода, используемого для реализации обмена (temp-swap, xor3-swap и т. Д.), Этот человек, похоже, слишком хорошо знаком с фундаментальными и довольно элементарными внутренними функциями функции.

Однако, как уже объяснялось, компилятор / компоновщик в общем случае помещает все строковые литералы в «const-сегмент данных» целевого исполняемого файла, который впоследствии ассоциируется с неписываемым дескриптором MMU во время соответствующего вызова «load / exec». Все циклы записи процессора, впоследствии выпущенные через этот дескриптор, автоматически захватываются механизмом исключения MMU, что приводит к обязательному эквиваленту «segfault» или платформе. Разумеется, на старых платформах, отличных от MMU, не было бы такого поведения.

Хотя это фактически обеспечивает поддержку во время выполнения для идиомы «константа / литерал» исходного языка, несколько платформ исторически облегчали явные переопределения сегментов компиляции. Однако этот уровень поддержки постепенно уменьшался в пользу более жесткого / надежного слоя абстракции, что делает многие очевидные и часто полезные оптимизации несостоятельными. Поскольку время и истощение приносят свою устойчивую старую философию «MC / ASM» до того, как все слишком нетерпеливое поколение «Microsoft», программисты больше не считаются осведомленными или ответственными, чтобы принимать такое решение. Вместо многих надуманных, а не творческих, реализаций, которые я видел в качестве руководителя проекта, это ни в коем случае не плохо.

Хотя этот пост быстро развивается в нарушение вне темы, я чувствую себя несколько оправданным постоянным streamом связанных с сверху вниз вопросов, которые медленно становятся эндемичными в нашей отрасли. Как молодой программист C – язык, первоначально разработанный для дополнения развития на низком уровне – мой совет – принять подход «снизу вверх» и расширить ваши исследования с помощью небольшого внеязыкового языка ассемблера. Поскольку алгоритмическая реализация, скорее всего, станет вашим основным направлением в качестве инженера-приложения, важно помнить, что современный дизайн ЦП испытывал однородную эволюцию за последние 30 лет; современные сверхбыстрые процессоры Intel – это не более чем суперскалярные CMOS-усовершенствования 4/8-битных биполярных процессоров, которые я программировал, когда Земля еще была молодой.

Вопреки распространенному мнению, программирование на ассемблере относительно легко учиться и абсолютно необходимо при попытке примирить конструкции высокого уровня с проблематичным или эзотерическим поведением. После того, как вы учитываете бесконечные часы экспериментов, отладки, веб-поиска и спама в форумах, не может быть никаких сомнений в том, что подход снизу вверх – это, конечно, путь наименьшего сопротивления.

Удачи вам в учебе.

Насколько я знаю, константные строки реализованы как массивы постоянных символов (или, в терминах C, const char [length] ). Поэтому вы не можете изменять свои символы.

Попробуйте динамически выделить строку.

 char* str = (char*)malloc(sizeof(char) * 4); strcpy(str, "abc"); str[3] = '\0'; 

Конечно, не забудьте освободить память в конце вашей программы.


Изменить: я не буду публиковать что-либо, связанное с изменением строки, потому что это ваша работа.

  • Что является результатом NULL + int?
  • Как распечатать адрес памяти в C
  • Является ли законным сравнивать висячие указатели?
  • Является ли segmentation fault действительным неопределенным поведением, когда мы ссылаемся на нестатический элемент данных
  • Как направить себя в UnsafeMutablePointer type в swift
  • Нарезка указателя среза, переданного в качестве аргумента
  • C typedef указателя на структуру
  • Почему cout печатает массивы char по-разному от других массивов?
  • Может ли указатель (адрес) быть отрицательным?
  • Указатель функции Typedef?
  • Размещение звездочки в Objective-C
  • Давайте будем гением компьютера.