Компилятор вправе создавать одинаковые строковые литералы либо раздавать указатели на один и тот же.
static char _str_test[5] = { 't','e','s','t',0 };
char* s = _str_test; // char* s = "test";char* t = _str_test; // char* t = "test";
Модификация строкового литерала приводит к отдаленным последействиям. Например,
void f(char* s)
{
if(strcmp(s, "test") == 0) printf("yes");
else printf("no");
}
void g()
{
char* t = "test";
t[0] = 'b';
}
main()
{
f("best"); // best != test --> no
g(); // test заменили на best
f("best"); // best == best --> yes
}
Поэтому компилятор С++ может (должен) считать, что строковый литерал имеет тип const char*.
Но для совместимости с голым Си это можно регулировать опциями.
Почему char s[] = "test" --- константа? Очень странно. Где-то у тебя очепятка.
... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
Re[2]: char* s = "test"; char s[] = "test"; объясните в чем
От:
Аноним
Дата:
25.04.03 14:51
Оценка:
Здравствуйте, Кодт, Вы писали:
<scip>
это понял
К>Почему char s[] = "test" --- константа? Очень странно. Где-то у тебя очепятка.
это отсутвие опыта(с++ — 3 месяца), почему-то думал что тип char всегда константный
почему так можно делать
char* s = "test";
s = "tost";
s = "testo";
s = "t";
а так нельзя
char s[] = "test";
s[2] = 'g'; //можно
s = "tost"; // no
s = "slkdjfsl"; //also no
Re[3]: char* s = "test"; char s[] = "test"; объясните в чем
Указателю s по очереди присваиваются адреса разных строковых литералов. Ты ведь не имеешь ничего против такого кода:
int i= 0;
i = 30;
i = 2;
А>а так нельзя
А>
А>char s[] = "test";
//s имеет тип char[5], т.е. массив. При инициализации в него копируется литерал "test"
А>s[2] = 'g'; //можно
//третьему элементу массива присвоено новое значение
А>s = "tost"; // no; s имеет тип char[5], а "tost" - char*. Типы разные, соответственно и присваивание запрещено
А>s = "slkdjfsl"; //also no - см. выше
А>
Любите книгу — источник знаний (с) М.Горький
Re[3]: char* s = "test"; char s[] = "test"; объясните в чем
А>char s[] = "test";
А>s[2] = 'g'; //можно
А>s = "tost"; // no
А>s = "slkdjfsl"; //also no
А>
Как присваивать строки и массивы.
1) строки: strcpy(куда, откуда) -- при этом "куда" должен иметь достаточно места.
2) POD (массивы и структуры простых данных): memcpy(куда, откуда, количество_байт)
3) хитрые данные — вручную или с использованием STL
Посмотри в документации (и в любом учебнике по Си) тему "работа со строками".
Там есть всякие нюансы.
Еще, возможно, тебе пригодится книга Язык Си в вопросах и ответах
Посмотри в книгах по С++ "стандартная библиотека шаблонов (STL)" — в ней есть реализации и массивов, и строк, и алгоритмов для них.
... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
Re[3]: char* s = "test"; char s[] = "test"; объясните в чем
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Кодт, Вы писали:
<scip> А>это понял
К>Почему char s[] = "test" --- константа? Очень странно. Где-то у тебя очепятка. А>это отсутвие опыта(с++ — 3 месяца), почему-то думал что тип char всегда константный
А>почему так можно делать
А>
потому что здесь ты вначале создаешь на стеке указатель, указывающий на строковый литерал, а потом просто переключаешь его, заставляя указывать на разные области памяти, где лежат твои остальные строковые литералы.
А>а так нельзя
А>
А>char s[] = "test";
А>s[2] = 'g'; //можно
А>s = "tost"; // no
А>s = "slkdjfsl"; //also no
А>
а когда ты объявляешь массив, ты прямо на стеке выделяешь соответствующее количество байт, и s — имя этого объекта на стеке, а не указатель на него. Соответственно во второй строчке ты говоришь: "а измени-ка мне в этом объекте на стеке второй символ" — и это, естественно, пройдет, а вот в третьей и четвертой ты говоришь: "а пусть теперь s указывает на строковый литерал" — а что прикажете делать с объектом на стеке? Так что при таком объявлении s не может быть изменена, можешь относиться к ней как к имеющей тип char * const (т.е. константный указатель на неконстантную строчку).
Короче так:
char* s = "test": s — указатель, переменная, которая хранит адресс памяти.
В данном случае это адресс первого элемента массива символов ( если не знаешь, то массивы
в памяти непрерывны, т.е. фрагментации нет, типа один кусок там а другой здесь, потому,
массив можно выловить через указатель на его первый элемент ).
char s[] = "test": s — массив символов.
В чем основной прикол: если работать с указателями, то мы работаем напрямую с памятью.
Есть также "синоним" указателя — ссылка. В синтаксисе работа со ссылкой
немного другая, чем с указателем. Тем не менее это практически одно и то же — ссылка
и указатель.
Преимущества использования указателей и ссылок: есть у тебя функция сортировки огромного массива
( ну допустим метров так 100 ). На сколько я знаю, нельзя из функции вернуть
массив ( возвращаемое значение ), но даже если тебе удастся это сделать, представь: когда
мы в эту функцию отдаем такой массив, то это приводит к выделению еще ста метров памяти —
функция создает копию массива. Вот. А если дать ссылку на массив, то функция не станет
создавать его копию, а станет работать с уже готовым.
Указатели вообще очень хорошая штука — в них вся мошь C++. Просто работота напрямую с
памятью быстрее, чем просто с переменными.
Еще один пример: оформил ты что-то в виде отдельного потока, но тебе надо использовать
некоторые функции из класса, создавшего этот поток. Берешь, и даешь потоку указатель
на самого себя (т.е. на класс) — this. А через указатель можно пробится к этим самым
функциям. Можно конечно тупо создать внутри потока объект класса, а если это, к примеру
главное диалоговое окно класса, и тебе в нем надо изменять значения некоторых переменных?
Например, пишешь ты копировщик файлов и функция копирования оформлена отдельным потоком
(так окно приложения не замораживается в ожидании завершения копирования),
а тебе же надо постоянно просматривать статус копирования... — через указатель достаешь
переменные класса окна и изменяешь их значения.
Конечно, во многих случаях можно обойтись и без указателей, но некоторые вещи без них
тяжело сделать, если вообще возможно.
Описание работы с указателями можно найти в любой книге по C++ для начинающих.