_basmp_ Не знаю на какой бумаге вы имеете ввиду, но этот код не собирается Код (Text): #include <iostream> using namespace std; int sumoflen(const char *words, const int N); int main(int argc, char **argv) { int N; int i = 0; cin >> N; cin.get(); char *words =new char[N+1]; cin.getline(words,N+1); cout << sumoflen(words,N); return 0; } int sumoflen(const char *words,const int N) { int sum = 0; sum = strlen(words); cout << words <<endl; words[0] = 'h'; cout << words << endl; return sum; } Вылетает ошибка: error C2166: l-value specifies const object И еще вопрос(надеюсь не тупой =) ), константная переменная, это результат работы препроцессора или все таки в памяти константная переменная отличается от обычной?
Зависит от реализации. Компилятор _может_ положить её в ro-область памяти, особенно, статическую переменную. Да и для автоматических применяются оптимизации, зависящие от константности. Правда, в последнем случае const - не более, чем спецификатор, т.к. компилятор всё равно увидит как снятие константности, так и неизменение данных, даже если они не помечены как константные.
IceStudent Спасибо огромное за разъяснение. diamond А вам спасибо за красивый метод const char * const*words --- И вообщем,всем спасибо! --- PS: помогите разобраться с конструкцией #define TEXTMATRIX(x, y) *(pTextMatrix + (y * nWindowCharsX) + x). То есть тут всего лишь строка pTextMatrix , но способ обращение к элементам интересный какой-то? Просто я хочу написать собственный вариант edit'а, и нужно получше понять делает pTextMatrix Код (Text): #include <windows.h> #define TEXTMATRIX(x, y) *(pTextMatrix + (y * nWindowCharsX) + x) // Глобальные переменные HINSTANCE hinst; // текущий экземпляр программы HBITMAP hCaret; // точечный рисунок каретки HDC hdc; // контекст устройства PAINTSTRUCT ps; // информация о прорисовке рабочей области static char *pTextMatrix = NULL; // указатель на текстовую матрицу static int nCharX, // ширина символа в логических единицах nCharY, // высота символа в логических единицах nWindowX, // ширина рабочей области nWindowY, // высота рабочей области nWindowCharsX, // ширина рабочей области для символа nWindowCharsY, // высота рабочей области для символа nCaretPosX, // x-координата каретки nCaretPosY; // y-координата каретки static UINT uOldBlink; // предыдущая частота мерцания int x, y; // x и y координаты, используемые в текстовой матрице TEXTMETRIC tm; // информация о фонте int c = 0; LONG WINAPI WndProc(HWND, UINT, WPARAM, LPARAM); char a = 0x30; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HWND hwnd; MSG msg; WNDCLASS w; memset(&w,0,sizeof(WNDCLASS)); w.style = CS_HREDRAW | CS_VREDRAW; w.lpfnWndProc = WndProc; w.hInstance = hInstance; w.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); w.lpszClassName = "My Class"; RegisterClass(&w); hwnd = CreateWindow(w.lpszClassName,"My new Tittle",WS_OVERLAPPEDWINDOW, 200,300,400,580,NULL,NULL,hInstance,NULL); ShowWindow(hwnd,nCmdShow); while (GetMessage(&msg, NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); UpdateWindow(hwnd); } return msg.wParam; } LONG WINAPI WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: // Выбор фиксированной ширины системного фонта и получение его текстовой матрицы. hdc = GetDC(hwnd); SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); GetTextMetrics(hdc, &tm); ReleaseDC(hwnd, hdc); // Сохранение средней высоты и ширины символов. nCharX = tm.tmAveCharWidth; nCharY = tm.tmHeight; return 0; case WM_SIZE: // Определение ширины рабочей области, в пикселях и в количестве символов. nWindowX = LOWORD(lParam); nWindowCharsX = max(1, nWindowX/nCharX); // Определение высоты рабочей области, в пикселях и в количестве символов. nWindowY = HIWORD(lParam); nWindowCharsY = max(1, nWindowY/nCharY); // Очистка буфера, который содержит введенный текст. if (pTextMatrix != NULL) free(pTextMatrix); // Если имеется достаточно памяти, распределите пространство для буфера ввода текста. pTextMatrix = malloc(nWindowCharsX * nWindowCharsY); if (pTextMatrix == NULL) ;//ErrorHandler("Not enough memory."); else for (y = 0; y < nWindowCharsY; y++) for (x = 0; x < nWindowCharsX; x++) TEXTMATRIX(x, y) = ' '; // Переместим каретку в начало координат SetCaretPos(0, 0); return 0; case WM_KEYDOWN: switch (wParam) { case VK_HOME: // в начало nCaretPosX = 0; break; case VK_END: // в конец nCaretPosX = nWindowCharsX - 1; break; case VK_PRIOR: // предыдущая страница nCaretPosY = 0; break; case VK_NEXT: // следующая страница nCaretPosY = nWindowCharsY -1; break; case VK_LEFT: // перемещение стрелкой влево nCaretPosX = max(nCaretPosX - 1, 0); break; case VK_RIGHT: // перемещение стрелкой вправо nCaretPosX = min(nCaretPosX + 1, nWindowCharsX - 1); break; case VK_UP: // перемещение стрелкой вверх nCaretPosY = max(nCaretPosY - 1, 0); break; case VK_DOWN: // перемещение стрелкой вниз nCaretPosY = min(nCaretPosY + 1, nWindowCharsY - 1); break; case VK_DELETE: // удалить // Переместите все символы, которые следовали за удаленным символом (на той же самой строке) на один // пробел обратно (влево) в матрице for (x = nCaretPosX; x < nWindowCharsX; x++) TEXTMATRIX(x, nCaretPosY) = TEXTMATRIX(x + 1, nCaretPosY); // Замена последнего символа в строке с пробелом. TEXTMATRIX(nWindowCharsX - 1, nCaretPosY) = ' '; // Прикладная программа будет рисовать вне обработки сообщения // WM_PAINT, так скрывают каретку. HideCaret(hwnd); // Перерисовка строки для удаленного символа. hdc = GetDC(hwnd); SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); TextOut(hdc, nCaretPosX * nCharX, nCaretPosY * nCharY, &TEXTMATRIX(nCaretPosX, nCaretPosY), nWindowCharsX - nCaretPosX); ReleaseDC(hwnd, hdc); // Показать каретку. ShowCaret(hwnd); break; } // Корректировать позицию каретки, основанную при обработке виртуальной клавиши SetCaretPos(nCaretPosX * nCharX, nCaretPosY * nCharY); return 0; case WM_CHAR: switch (wParam) { case 0x08: // Обратный Пробел (Back Space) // Перемещение каретки на один пробел, а затем обработка этого действия подобно клавише DEL. if (nCaretPosX > 0) { nCaretPosX--; SendMessage(hwnd, WM_KEYDOWN, VK_DELETE, 1L); } break; case 0x09: // табуляция (Tab) // Табуляция останавливается, проходя каждые четыре пробела, таким образом добавляются пробелы, // до тех пор, пока пользователь нажимает следующий раз на клавишу табуляции. do { SendMessage(hwnd, WM_CHAR, ' ', 1L); } while (nCaretPosX % 4 != 0); break; case 0x0D: // возврат каретки // Переход к началу следующей строки. Нижняя строка переносится по кругу в верхнюю часть. nCaretPosX = 0; if (++nCaretPosY == nWindowCharsY) nCaretPosY = 0; break; case 0x1B: // Escape case 0x0A: // перевод строки MessageBeep((UINT) -1); break; default: // Добавление символа в буфер текста. TEXTMATRIX(nCaretPosX, nCaretPosY) = (char) wParam; // Прикладная программа будет рисовать вне обработки сообщения WM_PAINT; так скрывают каретку. HideCaret(hwnd); // Прорисовка символа на экране hdc = GetDC(hwnd); SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); TextOut(hdc, nCaretPosX * nCharX, nCaretPosY * nCharY, &TEXTMATRIX(nCaretPosX, nCaretPosY), 1); ReleaseDC(hwnd, hdc); // Отобразим каретку ShowCaret(hwnd); // Подготовка переноса по словам с начала до конца, если Вы достигли конца строки if (++nCaretPosX == nWindowCharsX) { nCaretPosX = 0; if (++nCaretPosY == nWindowCharsY) nCaretPosY = 0; } break; } // Регулировка позиции каретки, основанной на обработке символа. SetCaretPos(nCaretPosX * nCharX, nCaretPosY * nCharY); return 0; case WM_PAINT: // Прорисовка всех символов в буфере, строка за строкой. hdc = BeginPaint(hwnd, &ps); SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); for (y = 0; y < nWindowCharsY; y++) TextOut(hdc, 0, y * nCharY, &TEXTMATRIX(0, y), nWindowCharsX); EndPaint(hwnd, &ps); break; case WM_SETFOCUS: // Окно имеет фокус ввода. Загрузка каретки определенной ресурсом программного приложения. hCaret = LoadBitmap(hinst, MAKEINTRESOURCE(120)); // Создание каретки CreateCaret(hwnd, hCaret, 0, 0); // Регулировка позиции каретки SetCaretPos(nCaretPosX * nCharX, nCaretPosY * nCharY); // Изображение каретки. ShowCaret(hwnd); break; case WM_KILLFOCUS: // Окно теряет фокус ввода, так что каретка уничтожается. DestroyCaret(); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, message, wParam, lParam); } return NULL; }
Макрос TEXTMATRIX возвращает символ (char) в позиции в буфере (экране), заданной соответствующей координатой (x,y). Точка_входа + (номер_строки * ширина_строки + номер_колонки). т.к. размер элемента равен 1 байт, то нет домножения содержимого скобки на размер элемента.
Я не очень хорошо знаю С и С++, особенно теорию. Спасибо, что одернули, зарвался.. Но код собирается на VC6 без варнингов (-W3 -GX). Код (Text): #include <iostream> using namespace std; int sumoflen(const char *words, const int N); int main(int argc, char **argv) { int N; int i = 0; cin >> N; cin.get(); char *words =new char[N+1]; cin.getline(words,N+1); cout << sumoflen(words,N); return 0; } int sumoflen(const char *words,const int N) { int sum = 0; sum = strlen(words); cout << words <<endl; ((char*)words)[0] = 'h'; cout << words << endl; return sum; } Вставлю свои пять копеек.. Если не верите просмотрите в отладчике код генерируемый тем-же VC (предположим, что вы включили оптимизацию). Компилер определяет как представить любую переменную исходя из ее использования в проге. Если она не используется, то ей может быть не выделено места вообще. Если только читается - она может генерироваться как константа. Если пишется ей будет выделена память (обычно в месте записи), а вот куда (в кучу, в стек, в дата секцию) зависит от алгоритма оптимизатора. Кроме того константным строкам перед передачей в функцию может выделяться память в куче с копированием их туда. Функции объявленые как инлайн могут не инлайнится, а ф-и не объявленные как инлайн могут инлайнится и оптимизироваться в пределах ф-и в которую заинлайнены. Таким образом все спецификаторы, типы, функции итд носят скорее рекомендательный характер. Те нет достаточно строгого соответствия между вашими сорцами и сгенерированым кодом (вообще-то оно есть в пределах одного компилера и одной оптимизации, но нет его описания и познается истина в процессе созерцания скомпиленого кода в дебугере).
_basmp_ Явное приведение типов. Предполагается, что в этом случае человек знает, что делает (хотя, бывает, что и не знает). Верно. Истина, но только по данному компилятору и даже его версии.
Ну в общем-то да. Кроме того на отладке, бывает полезно приводить типы даже в явных случаях. И еще Код (Text): int i=7643634; int j=(unsigned char)i; дает меньший код чем Код (Text): int i=7643634; int j=0xff & i; это о пользе явного приведения. сервис паку и ключам компиляции, но истина.
собственно все это замечательно но что мешает просто сделать приведение типов ?? Код (Text): #include <iostream> using namespace std; int sumoflen(const char **words, const int N); int main(int argc, char **argv) { const int size = 256; int N; int i = 0; cin >> N; cin.get(); char **mywords = new char*[N]; for (i = 0; i < N;i++) mywords[i] = new char[size-1]; while(i < N) cin.getline(mywords[i++],size-1); cout << sumoflen((const char**)mywords, N) << endl; return 0; } int sumoflen(const char **words,const int N) { int i; int sum = 0; for (i = 0; i < N; i++ ) sum += strlen(words[i]); return sum; }
зы для вас наверное это станет открытием что в .c это компилится а в .cpp нет по крайней мере в msvc 2008 а все почему ? потому что char * -> const char * можно а char ** -> const char ** нельзя иначе будет возможен хак как в примере в .cpp это запретили а в .c до сих пор работает Код (Text): #include <stdio.h> int main() { const char dds = 'j'; char * ty; const char ** cc; printf("%c\n", dds); cc = &ty; // хак в .c (msvc 2008) можно в .cpp нет *cc = &dds; *ty = 'k'; printf("%c\n", dds); } видите в чем соль ? если бы можно было присваивать char ** -> const char ** в отличии от char * -> const char * то стало бы возможным хитрым движением изменить константу