Форум программистов, компьютерный форум CyberForum.ru

char *s или char s[] - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 21, средняя оценка - 4.76
skvor
640KB мне хватило на всё.
118 / 49 / 2
Регистрация: 07.06.2009
Сообщений: 442
17.08.2011, 15:52     char *s или char s[] #1
C++
1
2
3
4
  char s1[]="1111",s2[]="2222";
  printf("%s %s\n",s1,s2);
  memmove(s1,s2,2);
  printf("%s %s\n",s1,s2);
работает нормально
C++
1
2
3
4
  char *s1="1111",*s2="2222";
  printf("%s %s\n",s1,s2);
  memmove(s1,s2,2);
  printf("%s %s\n",s1,s2);
компилируется с предупреждением
warning: deprecated conversion from string constant to 'char*'
и при запуске падает из-за memmove. Что собственно в этом плохого?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
mimicria
return (true);
 Аватар для mimicria
1956 / 1093 / 91
Регистрация: 19.04.2011
Сообщений: 2,344
17.08.2011, 15:54     char *s или char s[] #2
Выделение памяти
diagon
Higher
 Аватар для diagon
1920 / 1186 / 49
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
17.08.2011, 15:55     char *s или char s[] #3
В 1 случае память статически выделяется, во-втором просто объявляется указатель без всякого выделения памяти. А это не есть хорошо.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
17.08.2011, 16:07     char *s или char s[] #4
Выражение "1111" имеет тип const char *, вы же пытаетесь присвоить его переменной типа char *, отсюда предупреждение. Падает программа из-за memmove, поскольку, как уже было сказано, "1111" - константная строка и её нельзя изменить.
skvor
640KB мне хватило на всё.
118 / 49 / 2
Регистрация: 07.06.2009
Сообщений: 442
17.08.2011, 16:32  [ТС]     char *s или char s[] #5
Если s1 указатель на не-константу, то почему вообще возможна запись?
char *s1="что-то там";
И почему падает memcpy? Ну передали две ссылки на a и b, сказали сколько байт надо скопировать, а падать зачем?
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
17.08.2011, 16:34     char *s или char s[] #6
Цитата Сообщение от skvor Посмотреть сообщение
то почему вообще возможна запись
Неявное преобразование типа.
Цитата Сообщение от skvor Посмотреть сообщение
падать зачем
Потому что константы неизменны по определению.
Сыроежка
Заблокирован
17.08.2011, 16:41     char *s или char s[] #7
Цитата Сообщение от skvor Посмотреть сообщение
C++
1
2
3
4
  char s1[]="1111",s2[]="2222";
  printf("%s %s\n",s1,s2);
  memmove(s1,s2,2);
  printf("%s %s\n",s1,s2);
работает нормально
C++
1
2
3
4
  char *s1="1111",*s2="2222";
  printf("%s %s\n",s1,s2);
  memmove(s1,s2,2);
  printf("%s %s\n",s1,s2);
компилируется с предупреждением

и при запуске падает из-за memmove. Что собственно в этом плохого?
Во-втором случае вы инициализируете указатель значением, который указывает на строковый литерал. Согласно стандарту С++ строковый литерал имеет тип const char[], то есть массив констатных символов. Стандарт оставляет способ размещения литералов на усмотрение производлителей компиляторов. Например, совпадающие по значению литералы, то есть дублирующиеся литералы могут храниться в виде одного литерала. В свыязи с этим представьте себе такой код

C++
1
2
3
4
5
6
7
char *p = "Lex";
 
*p = 'S";
...
...
if ( strcmp( s, "Lex" ) == 0 )
/* и.т.д. */
Вы думаете, что с помощью функции strcmp вы сравниваете символьный массив 's' со значением "Lex", а на самом деле так как компилятор совпадающие строковые литералы может хранить в виде одного строкового литерала, то вы будете сравнивать не с "Lex", а с "Sex", так как строковый литерал был изменен!

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

В первом же случае, когда вы объявляете массив, то нимкакого строкового литерала в памяти не создается. Создается массив, который инициализируется значением выражениям инициализации. То есть в данном случае

char s1[]="1111";

создается массив s1, элементы которого получают значения '1', '1', '1', '1', '\0'. А сам строковый литерал, используемый в качестве выражения инициализации в памяти программы не сохраняется.
skvor
640KB мне хватило на всё.
118 / 49 / 2
Регистрация: 07.06.2009
Сообщений: 442
17.08.2011, 17:06  [ТС]     char *s или char s[] #8
Не имеет значения то на что указывает ссылка - константа или не-константа.
Ссылка указывает на участок памяти, и в программе этот участок никак не маркируется.
Если ссылка на константу, то сам компилятор не должен разрешать выражения меняющие значение.
При запуске программы по ссылке s1 находится пять байтов "1111\0". То что данные взяты из константного выражения уже не имеет значения - s1 является указателем на char.

Добавлено через 4 минуты
Сыроежка, пожалуйста, читайте внимательно, а не по диагонали через пять строк.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
17.08.2011, 17:08     char *s или char s[] #9
skvor, я не понимаю, чего вы добиваетесь? Вам уже сказали причину - строковый литерал располагается в read-only памяти, менять такую память запрещено, попытка приводит к печальным последствиям. Вы хоть указатель на int установите указывать на эту read-only память, результат будет всё тем же плачевным. Важно не то, какой тип имеет указатель, а то, какой тип имеет объект, на который этот указатель указывает.

Добавлено через 1 минуту
И не надо ваших предположений по поводу того, что компилятор должен делать и чего не должен. Они могут оказаться чрезвычайно далеки от истины.
grizlik78
Эксперт C++
 Аватар для grizlik78
1882 / 1414 / 101
Регистрация: 29.05.2011
Сообщений: 2,958
17.08.2011, 17:16     char *s или char s[] #10
Цитата Сообщение от skvor Посмотреть сообщение
Если ссылка на константу, то сам компилятор не должен разрешать выражения меняющие значение.
Если внимательно посмотреть на предупреждение, то можно увидеть там слово deprecated. Это наследие старины глубокой, скорее всего даже из языка Си пришедшее. Это неявное преобразование рады бы запретить, но если делать это сразу, то сломается довольно много старого кода. Вы же всегда можете включить опцию компилятора, которая считает предупреждения ошибками, тем более что часто это так и есть, как и в данном случае.
Сыроежка
Заблокирован
17.08.2011, 20:55     char *s или char s[] #11
Цитата Сообщение от skvor Посмотреть сообщение
Не имеет значения то на что указывает ссылка - константа или не-константа.
Ссылка указывает на участок памяти, и в программе этот участок никак не маркируется.
Если ссылка на константу, то сам компилятор не должен разрешать выражения меняющие значение.
При запуске программы по ссылке s1 находится пять байтов "1111\0". То что данные взяты из константного выражения уже не имеет значения - s1 является указателем на char.

Добавлено через 4 минуты
Сыроежка, пожалуйста, читайте внимательно, а не по диагонали через пять строк.
Я совершенно не понял, что вас не устроило в моем ответе! Не можете ли разъяснить, чем вы не довольны?!

Добавлено через 5 минут
Цитата Сообщение от grizlik78 Посмотреть сообщение
Если внимательно посмотреть на предупреждение, то можно увидеть там слово deprecated. Это наследие старины глубокой, скорее всего даже из языка Си пришедшее. Это неявное преобразование рады бы запретить, но если делать это сразу, то сломается довольно много старого кода. Вы же всегда можете включить опцию компилятора, которая считает предупреждения ошибками, тем более что часто это так и есть, как и в данном случае.
На самом деле это не неявное преобразование, а явное! Я понимаю, что вы мне сейчас сделаете ссылку на приложение D стандарта, где говорится о неячвном преобразовании. Но на самом деле в другом месте стандарта говорится, что такое преобразование может иметь место только при явном преобразовании! Это одно из тех мест стандарта, где стандарт сам себе противоречит.
Что значит "явное преобразование"? Это преобразование вида
C++
1
chat *p = "ABC";
То есть вы явно указываете тип результирующего выражения.

При неявном преобразовании строковый литерал как раз преобразуется в выражениях (кроме ссылок на них) в
C++
1
const char *
.
grizlik78
17.08.2011, 21:00
  #12

Не по теме:

Цитата Сообщение от Сыроежка Посмотреть сообщение
На самом деле это не неявное преобразование, а явное!
Ну и зануда же, а? Слово неявное в моём сообщении вообще никакой роли не играло.

Сыроежка
Заблокирован
17.08.2011, 21:37     char *s или char s[] #13
Цитата Сообщение от grizlik78 Посмотреть сообщение

Не по теме:


Ну и зануда же, а? Слово неявное в моём сообщении вообще никакой роли не играло.

Если слово никакой роли не играет , то и не следует им засорять речь!
grizlik78
Эксперт C++
 Аватар для grizlik78
1882 / 1414 / 101
Регистрация: 29.05.2011
Сообщений: 2,958
17.08.2011, 21:43     char *s или char s[] #14
Преобразование там, конечно же, неявное, что ж с этим поделать-то? Почему же на основании чьих-то заблуждений я должен выкидывать слово из предложения? Но если читателю оно не по душе, он может смело его выкинуть, смысл от этого нисколечко не изменится.
Кроме того, говоря "Это неявное преобразование" я подразумевал не только выражение типа
C++
1
char const *s = "abc";
но и выражение
C++
1
some_func("abc");
где в прототипе используется тип char*. Или в этом месте преобразование тоже явное?
Сыроежка
Заблокирован
17.08.2011, 21:49     char *s или char s[] #15
Цитата Сообщение от grizlik78 Посмотреть сообщение
Преобразование там, конечно же, неявное, что ж с этим поделать-то? Почему же на основании чьих-то заблуждений я должен выкидывать слово из предложения? Но если читателю оно не по душе, он может смело его выкинуть, смысл от этого нисколечко не изменится.
Кроме того, говоря "Это неявное преобразование" я подразумевал не только выражение типа
C++
1
char const *s = "abc";
но и выражение
C++
1
some_func("abc");
где в прототипе используется тип char*. Или в этом месте преобразование тоже явное?
Второе выражение тоже является явным преобразованием так как параметры вычисляются на основе оператора присваивания. То есть этот пример полностью аналогичен первому, если у функции параметр объявлен как char *.

Как я уже ранее отметил, в этом вопросе в стандарте присутствует путаница. Я все же согласен с тем, что когда явно указывается тип результата, как в операторе присваивания, или в объявлении, то это явное преобразование.
grizlik78
Эксперт C++
 Аватар для grizlik78
1882 / 1414 / 101
Регистрация: 29.05.2011
Сообщений: 2,958
17.08.2011, 21:50     char *s или char s[] #16
Хотелось бы увидеть ссылку на то место в стандарте, которое позволяет трактовать это таким образом.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
18.08.2011, 03:53     char *s или char s[]
Еще ссылки по теме:

C++ string[] в char[][] или char[]
array char* to char* (значения массива указателей в один указатель) C++
Преобразование char в char* или разделить на две строки C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
accept
4837 / 3236 / 165
Регистрация: 10.12.2008
Сообщений: 10,682
18.08.2011, 03:53     char *s или char s[] #17
Цитата Сообщение от Сыроежка
На самом деле это не неявное преобразование, а явное!
явное преобразование типа - это через операцию приведения типа

C
1
char *p = (char *) "abcd";
это сработает без предупреждения, так как не отбрасывается const

операция присваивания имеет ряд ограничений
C89 (draft) 3.3.16.1 Simple assignment
* both operands are pointers to qualified or unqualified versions of
compatible types, and the type pointed to by the left has all the
qualifiers of the type pointed to by the right;
Yandex
Объявления
18.08.2011, 03:53     char *s или char s[]
Ответ Создать тему

Метки
memmove, массивы, работа с памятью, Строки, указатели
Опции темы

Текущее время: 03:25. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru