Не вопрос!..
Типы данных.Сказанное ниже гарантировано
соотносится со спецификациями Си/Си++. Наверняка во многих других языках
действуют похожие правила.
1. Простые типы данных.К
простым типам относят: одиночные символы, любые числовые переменные и
пр.
Код |
char ch;// один 8-битный символ (в разных компиляторах может
быть unsigned или signed) unsigned char uch;// гарантированно беззнаковая
8-битная переменная; байт проще говоря signed char sch;// гарантировано
знаковая 8-битная переменная; минус один бит на знак int i;// целочисленная
переменная со знаком unsigned int ui;// целочисленная переменная без
знака float fl;// число с плавающей
точкой
|
2. Сложные типы данных.
К сложным
типам данных относят для Си - структуры, объединения и массивы; для Си++ - тоже
+ классы. Сложные типы можно также назвать составными, т.к. они в конечном итоге
всё равно содержат в себе простые (сложный тип = набор простых). Важно понять,
что процессор не умеет работать со сложными типами. Он не может понять, что
такое std::string или char[10]. Для него это - набор простых типов. Программист
так же никогда не работает со сложными типами напрямую - он работает только с
указателями на сложные типы. Что это такое разберём дальше.
3.
Указатели.
Любой указатель принадлежит простому типу и содержит в
себе адрес определённой ячейки памяти. Чаще всего в 32-битных процессорах x86
используют 32-битные же указатели. Проще говоря, в большинстве случаев любой
указатель имеет тип unsigned int. Программист работает со сложными объектами
только при помощи указателей. Даже когда он видит перед собой объект типом
char[10] он должен знать, что это - лишь указатель на область памяти, где
находится десять переменных простого типа char. Типы int* и int[] абсолютно
идеинтичны - это указатели на массивы памяти. Разница только в одном: один из
этих указателей динамический, а другой статический. Что это такое? Проще
пояснить примером:
Код |
int iArray[10];// Создаётся десять переменных типом int
следующих в памяти друг за другом и тут же - // создаётся константа(!) типом
int* - указатель; причём переменной "указатель" тут же автоматически //
присваивается значение адреса десяти int-овых переменных - всё в одной
строчке!
int* pInt;// Создаётся только(!) переменная типом int*; никакого
массива мы ещё не получили! pInt = new int[10];// Вот теперь всё в порядке;
функция(в Си - оператор) new создаёт десять // переменных типом int и
возвращает адрес на первую из этих переменных, который // присваивается
переменной-указателю pInt
|
Первый массив называют статическим, второй -
динамическим. Соответственно, переменная iArray - статическая, pInt -
динамическая. Кстати, если вы напишете вот это:
То вы получите десять переменных-указателей и ни
одного массива. Чтобы получать массивы динамическим образом ("на ходу")
вам необходимо самостоятельно вызвать оператор new или функцию выделения памяти
и после завершения использования - удалить массив вызовом delete или функцией
освобождения памяти. Со статическими массивами проще - там компилятор сам решает
где взять память и когда её освободить, причём делает и то и другое с
необыкновенной быстротой, потому как всё это определяется ещё на моменте
компиляции, а не в процессе исполнения. Казалось бы, все преимущества
статических переменных на лицо, зачем же использовать динамические? Не
торопитесь.
Код |
int* i = new int;// Тоже массив, кстати. Правда содержит
всего один элемент... // какие-то операции с i delete i;// Освобождаем
старый массив (указатель никуда не девается!) i = new int [10];// Создаём
новый, значительно больше прежнего
int iA[10]; delete iA;//
Ошибка! iA = new int[12];// Тоже самое...
int nElements = 0; //
Вычисление значения nElements int iArray[nElements];// Ошибка! Рамер должен
быть константным! int pArray = new int[nElements];// Никаких проблем, всё
работает...
|
Теперь можно привести примеры с
извечной проблемой строк, которая проблемой по сути является только для новичков
(камень в огород Си-ненавистников).
Код |
char* str = "STRING";// Глупо выглядит, но эта строчка -
работает! strcpy(str, "А вот эта -
нет");
|
Почему
первая строка работает, а вторая - сбоит? Всё просто. "STRING" - константный
набор данных. Откройте свою программу любым текстовым редактором - вы там без
труда найдёте эту строку. В первой строке вышеприведённого кода происходит
присвоение указателю char* str адреса константной области данных, содержащей
"STRING". При попытке изменить эту область операционная система даёт нам оплеуху
и выкидывает программу из списка процессов. Вот этот код работает:
Код |
char* str = "STRING";// Тишина... и мёртвы с косами
ходят... char* s = new char[7]; strcpy(s, str);// Ей богу, на воровство
похоже!
|
Лучше такой экзотикой не заниматься, а
писать сразу в вызов функции strcpy строку "STRING", потому как никто не
гарантирует, что где-нибудь в губине кода не произойдёт
следующее:
Код |
str[3] = 'O';// Забыли мы где находимся
:-)
|