![]() |
При программировании строк в Visual C++ и под Linux я заметил такую штуку:
Если обявить строку как char* pch = "Some_string" то операция *pch = 'A' приводит к ошибкам выполнения. В Linux пишет Segmentation Fail т.е. ошибка обращения к памяти. И в тоже время объявление char pch[] = "Some_string" и операция *pch = 'A' отрабатывает нормально без всяких глюков. Может кто знает где здесь собака зарыта. Только если можно поподробнее. Я думаю это как-то связано с защитой памяти в ОС или что-то в этом духе |
char pch[] = "Some_string"
мне кажется понятно, почему работает, по той же причине, что и char pch[10] = "Some_string" , только цифры компилятор сам подставляет, т.е. память он выделяет все-таки под переменную, а char* pch = "Some_string" память не выделяет, и хранит значение в другом месте. И хочу заметить что не будет доступно и pch[3]='A' вызовет ту же ошибку. Или вопрос был где именно хранится значение переменной? |
для строки *char - надо так:
char *point,*psh="Some_string"; .... point=psh; point='A' pch='B' ... point=pch+1 point='A' А что по вашему должна делать команда *pch='A' ? - записать по адресу, указанному в pch значение 'A' ? Т.е по адресу 0x00129 записать 0x100 ? |
Вообще-то в C++ строковые литералы имеют тип const char * и char * s = "string literal" оставили только для совместимости со старым кодом. Правильнее будет const char * s = "string literal".
Добавлено: Соответственно объявление char s[] = "string" это объявление обычного массива. |
ruslandh
Вынужден разочаровать, но ты не прав. Цитата:
point = pch+1; //Правомерно, point указывает на второй символ строки. point = 'A'; // pch='B'; * * // А вот так нельзя. Указателю нельзя присваивать неадресные значения. Надо именно: *point = 'A'; *pch = 'B'; //Т.е. по адресам, куда они указывают записываются значения того типа, указателями на которые они являются. Это эквивалентно записи: point[0] = 'A'; pch[0] = 'B'; Другое дело, что как сказал ivank, в первом случае была попытка через указатель изменить значение константы. [s]Исправлено: shurikan, 1:56 7-04-2003[/s] |
ребята, вас память выделять не учили?
|
Vaulter
А к данному случаю это отношения не имеет. Под литерал память выделяет компилятор и под указатель тоже. А потом в ячейку указателя кладёт адрес литерала... Извини... |
shurikan
Ты не совсем прав, что это не имеет отношения к выделению памяти. char* pch = "Some_string" В этом случае в стеке создается pch, в сегменте данных - КОНСТАНТА "Some_string", и pch инициализируется адресом константы. Менять значение указателя можно без проблем, а вот в "Some_string" писать нельзя именно из-за того, что под нее так выделена память. char pch[] = "Some_string" На стеке создается массив pch[] и его элементы инициализируются значениями из строковой константы (в принципе, компилятор мог бы, как и в прошлый раз, выделить место с сегменте данных, а после создания pch[] написать какой-нибудь memcpy, если эта константа много где встречается и так будет компактнее). То есть, "Some_string" как таковой может и вовсе не существовать. Естественно, в pch[] можно писать. Цитата:
x = "x2"; x = "x3"; и т.д. |
vasketsov
Верно для локальных переменных, а если они глобальные? Для них память выделяется в сегменте данных. А результат выражения "x2" - есть адрес, так что это адресное выражение. |
shurikan
Цитата:
Цитата:
WCHAR x[] = L"sss"; то L"sss" - никакое не "адресное выражение", а параметр инициализации x[]. То есть, у L"sss" может вовсе не быть адреса. |
Раз вы так все хорошо со строками ориентируетесь, то объясните такую вещь:
Visual C++ С помощью CListCtrl создаю свой собственный класс списка (использую пример, естественно), где каждый элемент списка представляет собой кнопку. Для отрисовки строк используется процедура Код:
DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) CString str="Some String"; m_List.AddString(str); * на экране галиматья, т.е. любое использование локальных для данной процедуры переменных приводит к тому, что данные не отображаются. если использовать char str=new char[20]; ... то все отображается, но при попытке delete str[] все накрывается, потому что список использует эти значения Итог такой работает только если самостоятельно плодить утечку памяти, где ж это все хранится? сама функция DrawItem использует не адрес а число, адрес содержащее, и в чем загвоздка не пойму [s]Исправлено: Crew, 23:14 7-04-2003[/s] |
Crew
> Или вопрос был где именно хранится значение переменной? Да вопрос как раз в этом то и заключался, то что будут ошибки так это я сам знаю. Почему? ruslandh А что по вашему должна делать команда *pch='A' ? - записать по адресу, указанному в pch значение 'A' ? Т.е по адресу 0x00129 записать 0x100 ? Фишка в том что *pch - разименование указателя. Т.е. 'A' будет записано в ячейку, адрес которой содержится в pch. Vaulter Так если объявление char* pch = "Some_String"; не выделяет память то куда же она будет записана. Ведь вывести я ее могу? |
VBMUSTDIE
освободить то ее надо потом ) хотя это будут Memory leaks |
Знаете в чем еще фишка. Если сделать Active Confoguration не Debug а Release все работает. Вообще какая-то фигня
:( |
VBMUSTDIE
в Debug режиме, VC запускает прогу в своей куче. |
Crew
Меня очень ломает разбираться в MFC, потому давайте вместе. Какие прототипы есть у вызова AddString? То есть, что можно передать этой функции (без учета приведения типа непосредственно внутри скобочек)? Есть мысль, что AddString просто берет указатель на строку, если у тебя строчка в сегменте данных, то работать будет, если через CString - то ты отдаешь в лист указатель на CString-овую строку - при прибитии его тебе программа вполне обосновано дает по рукам, так как адрес, сохраненный в твоем листе, уже толком никуда не указывает. Аналогично и с массивом, пока не убьешь его, все будет работать. Vaulter Цитата:
Я собрал проект как Debug. Закрыл к чертям MSVC. Запустил собранный проект. Откуда он возьмет кучу MSVC? |
Vaulter
Когда я выше упоминал, что к выделению памяти этот случай не имеет отношения, я имел ввиду динамическое выделение памяти. Слово "динамическое" я опустил, за что справедливо получил по шапке от vasketsov-а. Так вот, если память выделяется динамически с помощью всяких там new, malloc и им подобных, то память нужно освобождать, а если (как написано) Код:
char *pch = "Some string"; |
VBMUSTDIE
скажу всетаки секрет один: char* a="something"; "а" вообще то будет распознана компилятором как строковая константа: const char a[9]; поэтому и нельзя a[4]='a'; а вот char a[]="something"; можно. потому как будет "а" будет как char a[9]; |
vasketsov
AddString может принимать как CString, так и char * функция прорисовки в любом случае получает только DWORD, вытаскивать что там такое моя задача (несложная) Я трейсером смотрел все она передает, но только почему-то (трейсер не улавливает) перерисовывает эти данные не один раз а три. Но ладно бы так как я делаю, но я удалить не могу эти строки (которые создаю), иначе на экран выводится "ЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭ" причем удалить не могу ни до, ни после отрисовки, потому-что она еще раз вызывается. и если я удаляю после AddString, оно понятно почему накрывается. А если в DrawItem(...) Код:
* *const char*s=_T(LPCTSTR(lpDrawItemStruct->itemData)); Vaulter Цитирую из книги "Программирование на VC++ 6.0" серия для профессионалов Чтобы константы гарантированно хранились вместе с программой, придется немного поработать. Во превых, обратите внимание на строковые константы, которыми часто изобилуют программы. Может, Вы решили, что они будут данными "только для чтения"? Тогда попробуйте угадать еще раз. Действительно, поскольку Вы имеете право написать что-нибудь вроде Код:
char *pch ="test"; Код:
const char g_pch[]="test"; ... Имя * * *Тип * * * * * Доступ * * * * * * * * * * Содержимое .text * * код * * * * * *только чтение * * * * *код программы .rdata * данные * * только чтение * * * * *инициализированные константы .data * *данные * * *чтение и запись * * *инициализированные данные (не кон) .bss * * данные * * * чтение и запись * * неинициализ данные (не кон) Секция .rdata - часть EXE файла, именно сюда компоновщик поместит переменную g_pch. Из всего вышесказанного становится непонятно почему не работает код, ставшей причиной этого топика :) [s]Исправлено: Crew, 0:04 10-04-2003[/s] |
Цитата:
Пример 1. Цитата:
Пример 2. Цитата:
Код:
void x(void) А вот "test" может быть как в стеке (прямо здесь же, зачем ее иметь в других местах?), а может быть и в секции данных (если "test" много и компилятор решил заняться оптимизацией). Crew Попробуй сделать так void addx(идентификация листа, напр., указатель на него) { char x[8] = "йцукен"; x[0]='q'; //чтоб не оптимизировалось твой Add(x) } [/code] если вылетит - придется либо глобальные строчки использовать, либо руками память выделять/освобождать (освобождать можно при наступлении события удаления элемента, вроде там такое есть, по крайней мере винда такое сообщение шлет). |
Цитата:
vasketsov Преложенный код вывел %МB_-ьd при добавлении слова static, заработало, но в цикле использовать переменную не могу, потому что Код:
static char x[8]="йцукен"; 2йцукен а заранее предсказать количество строк в списке я не могу, не делать же массив глобальных переменных? Я правильно понял идею с глобальными пременными? Цитата:
|
Так что я могу положить сколь угодно большое число в
char *point="asdfasdfsad....n" это както небезопасно получается. Меня почемуто это больше всего тревожит. А не обрашение к ниму. [s]Исправлено: glassMonk, 3:25 11-04-2003[/s] |
Crew
Если AddString действительно может принимать pchar, можешь сделать так, вроде противопоказаний нет: Цитата:
|
vasketsov
Цитата:
char* pch = "Some_String" память не выделяется? Но если попробовать вести строку в ЛЮБОМ месте программы то она выведится printf("%s\n", pch); Как так память не выделяется а функция выводит? |
vasketsov
Зачем мне это?. Мне строки днамически создавать надо. а так и AddString("Some string"); прекрасно работает. Мне это вообще зачем нужно - это достаточно большая база с вопросами, где выбрав нужный ответ, нажав на кнопку с текстом ответа, уменьшаем время, затрачиваемое на прохождение теста. Вопросы берутся из базы, в виде переменных -естественно. VBMUSTDIE Я так для себя упростил, что записалась эта строка куда-то в ЕХЕ, компилятор делает вид что это обычный адрес, однако разрешает только читать из самого себя и только столько, сколько при компиляции отведено, и любые попытки поменять значения воспринимает как попытки поменять сам ЕХЕ. |
Crew
Сделай глобальный CList (или как там аналог std::list называется?) строк и заполняй его динамически по мере надобности. Цитата:
Цитата:
|
VBMUSTDIE
Цитата:
Цитата:
2) Если только %s, то нетрудно видеть, чтоб можно вывести этот текст без дополнительного выделения памяти даже на стеке. Выводим текст до %s, потом аргумент, потом снова текст до %s, снова аргумент, и т.д. 3) Если есть %d и т.п., то сложнее, но память может выделиться внутри printf (особенно если ей на вход отдается свой нетривиальный объект) и освободиться там же. |
glassMonk
Цитата:
|
Ответ оказался в цитате, я догадался сам.
|
int len=strlen(name);
char* buffer = new char[2*sizeof(int)+len]; memcpy(buffer,&len,sizeof(int)); memcpy(buffer+sizeof(int),name,len); memcpy(buffer+sizeof(int)+len,&age,sizeof(int)); return buffer; почему после этого в буфере пусто? |
Guest
Это что, попытка превратить C-строку в Pascal-строку? Pascal-строка (короткая) содержит длину в одном (первом) байте. А размер данных типа int зависит от ОС и компилятора - м.б. 2 байта, а м.б *- 4. В любом случае старшие байты переменной len, скорее всего нулевые. А что такое age? |
Время: 07:29. |
Время: 07:29.
© OSzone.net 2001-