Увеличение символа в строковом литерале

    #include<stdio.h>
    int main(){
       char *ptr="Helio";
       ptr++;
       printf("%s\n",ptr);
       //*ptr++;
       printf("%c\n",++*ptr);/*Segmentation fault on GCC*/
       return 0;
    }

Q1) Это прекрасно работает в Turbo C++, но в GCC возникает ошибка сегментации. Я не улавливаю точную причину.

Может быть приоритет оператора является одной из причин.

Q2) У каждого компилятора разный приоритет операций?

Как я вижу здесь ++ имеет более высокий приоритет, чем оператор разыменования. Возможно, GCC и Turbo C++ относятся к ним по-разному.


person anuj pradhan    schedule 15.07.2014    source источник
comment
нет, это потому, что вы указываете на постоянную строку, но вы разыменовываете первый символ   -  person v.oddou    schedule 15.07.2014
comment
вы хотите увеличить ptr или значение в ptr[0]?   -  person mohitj2007    schedule 15.07.2014
comment
Приоритет оператора не может быть проблемой... (++*)ptr недопустимый синтаксис!   -  person M.M    schedule 15.07.2014
comment
@MattMcNabb, но это будет иметь значение в закомментированной строке, без скобок это эквивалентно *(ptr++). Возможно, именно это и сбивает с толку, ведь поведение этих двух форм совершенно разное.   -  person Mark Ransom    schedule 15.07.2014


Ответы (3)


Нет, приоритет оператора определяется стандартом C, все компиляторы следуют одному и тому же.

Причина различия результатов Turbo C++ и GCC в этом случае заключается в том, что вы изменили строковый литерал, что является неопределенным поведением.

Измените его на:

char arr[] = "Helio";
char *ptr = arr;

и теперь вы можете изменить содержимое строки. Обратите внимание, что arr само по себе является именем массива и не может быть изменено, поэтому я добавил новую переменную-указатель ptr и инициализировал ее так, чтобы она указывала на первый элемент массива.

person Yu Hao    schedule 15.07.2014

В вашей последней printf() строке выражение ++*ptr эквивалентно ++ptr[0], которое, в свою очередь, эквивалентно ptr[0] = ptr[0]+1. Начиная с ptr[0]=='H', вы пытаетесь изменить значение ptr[0] на 'I'.

Это ключевая проблема там. Поскольку &ptr[0] указывает на первый элемент константы "Helio", попытка изменить первый символ, H, вызывает проблемы, поскольку это Undefined Behavior.

person pablo1977    schedule 15.07.2014
comment
@ v.oddou +1, это хорошая попытка дать правильный ответ :). За это нельзя голосовать против. - person Jayesh Bhoi; 15.07.2014
comment
@v.oddou: Мой ответ очень простой и очень стандартный, поэтому у него нет настоящего владельца. Там нечего плагиатить. Ваш ответ начните с неправильного понятия. С другой стороны, Ю Хао не совсем ясен в центральном вопросе. Поэтому я решил дать четкий и простой ответ. Джайеш хорошо понимал ситуацию. - person pablo1977; 15.07.2014
comment
@ pablo1977: я отредактировал его, поэтому начало с неправильной концепцией больше не применяется. И, на мой взгляд, никогда не было, но это только я. Вы правы во всем остальном. Но, пожалуйста, поймите, что мне откровенно горько из-за того, что люди просто решили слепо следовать замечанию quantdev и практически сделали мой ответ невидимым сейчас, когда на самом деле он говорит больше, чем ваш, и у вас уже есть голос. где эта ярмарка - person v.oddou; 15.07.2014
comment
@v.oddou, почему несправедливо проголосовать за хороший ответ? никто не заставит никого использовать синтаксис, подобный этому или подобному этому. Оставьте это на компиляторе, это будет лучше всего. В любом случае, ваша попытка хороша, и вы оценили все комментарии. продолжайте в том же духе. +1 для вас, когда вы сделаете в нем издание. - person Jayesh Bhoi; 15.07.2014
comment
@Jayesh: спасибо :) Я ценю. Я много редактировал, чтобы все были довольны. - person v.oddou; 15.07.2014
comment
@v.oddou Во-первых, этот ответ не тратит место на обсуждение «C-людей» и их вонючих идей. Так что это не плагиат на мой взгляд. И наоборот, вы можете принять этот ответ как источник вдохновения для того, как должен выглядеть ответ SO. - person Pascal Cuoq; 15.07.2014

char* p = "some literal";

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

Это сообщение, которое вы получаете с GCC:

предупреждение: устарело преобразование из строковой константы в 'char*'

Пожалуйста, в следующий раз напишите следующее:

char const* p = "some literal";

И сделайте это рефлексом в ваших привычках кодирования. Тогда вы не смогли бы скомпилировать свою ошибочную строку.

который:

++*ptr

Здесь вы берете первый символ постоянного литерала и пытаетесь увеличить его до того, что идет после H, следовательно, I. Но эта зона памяти оказывается на защищенной от записи странице, потому что это константа. Это очень не определено стандартом, и вы должны считать это незаконным. Ваш segfault исходит отсюда. Я предлагаю вам запустить вашу программу в valgrind в следующий раз, чтобы получить более подробные сообщения об ошибках.

В ответе, который Ю Хао написал для вас, происходит то, что все символы копируются один за другим из пула константных строк, где хранится литерал, в массив символов, выделенный стеком, с помощью кода, который пишет компилятор на сайте инициализации/объявления, поэтому вы можете разыменовать его содержимое.

person v.oddou    schedule 15.07.2014
comment
Это не незаконное заявление - person quantdev; 15.07.2014
comment
вы должны считать, как это. потому что вы const бросаете от const к non const. пока вы получаете доступ только для чтения, все в порядке, но доступ для записи и бум. некоторые компиляторы выдают ошибки сборки при таком объявлении. - person v.oddou; 15.07.2014
comment
более подробно здесь: stackoverflow.com/questions/3075049/ - person v.oddou; 15.07.2014
comment
@v.oddou все правильно, например, изменение строкового литерала является незаконным, потому что оно находится в части только для чтения. Но это заявление не является незаконным. он просто создал указатель и указал его на постоянную строку. Так исправьте это сначала. - person Jayesh Bhoi; 15.07.2014
comment
@Jayesh: спасибо, я понял вашу точку зрения и отредактировал спорную строку, чтобы она соответствовала педантичным настроениям сообщества. С другой стороны, я сделал свое выражение очень ясным, используя расширенную фразу того, что я передал, используя предыдущую формулировку, за которую меня проголосовали. На самом деле я чувствую себя довольно сбитым с толку этим весельем с отрицательным голосованием, у меня такое чувство, что достаточно одного человека, чтобы почесаться в педантичной части терминологии, чтобы группа других людей собралась здесь, о, его вечеринка с отрицательным голосованием, ура! ... Что ж... - person v.oddou; 15.07.2014
comment
Я не минусовал, но чувствую, что выбор точной формулировки очень важен, а не педантичен, и это единственный способ перейти на сайт контроля качества, такой как StackOverflow. Новичок мог бы легко прочитать вас, потому что это незаконно! Он не должен компилироваться! так почему мой компилятор компилирует это?!. Быть требовательным полезно для всех. - person quantdev; 15.07.2014
comment
@quantdev Но это устарело в C ++. Так что это на пути к тому, чтобы быть незаконным. Последний компилятор C++ должен выдать вам предупреждение. - person juanchopanza; 15.07.2014
comment
@juanchopanza: да, я отредактировал ответ, чтобы подчеркнуть этот факт :) - person v.oddou; 15.07.2014
comment
@v.oddou +1. Теперь это выглядит кучей подходящих деталей. - person Jayesh Bhoi; 15.07.2014
comment
@Jayesh: это благодаря критике сообщества. Можно сказать, что это заставило меня изложить все в чистом виде. Однако я буду помнить жестокость, с которой это произошло, и воздержусь от помощи людям в будущем. - person v.oddou; 15.07.2014