- •Оглавление
- •Введение
- •Общие положения
- •Структура рабочего стола среды программирования
- •Главное окно
- •Некоторые замечания
- •О рабочем столе
- •О справочной системе Help
- •Структура программ в VC++
- •Переход к созданию консольного приложения
- •Программа с оператором while
- •Имена и типы переменных
- •Оператор while
- •Оператор for
- •Символические константы
- •Глава 2. Программы для работы с символьными данными
- •Программа копирования символьного файла. Вариант 1
- •Программа копирования символьного файла. Вариант 2
- •Подсчет символов в файле. Вариант 1
- •Подсчет символов в файле. Вариант 2
- •Подсчет количества строк в файле
- •Подсчет количества слов в файле
- •Глава 3. Работа с массивами данных
- •Одномерные массивы
- •Многомерные массивы
- •Глава 4. Создание и использование функций
- •Создание некоторых функций
- •Ввод строки с клавиатуры
- •Функция выделения подстроки из строки
- •Функция копирования строки в строку
- •Внешние и внутренние переменные
- •Область действия переменных
- •Как создать свой внешний файл
- •Атрибут static
- •Рекурсивные функции
- •Некоторые итоговые данные по изучению функций
- •Перегрузка функций
- •Использование шаблонов функций
- •Создание простого шаблона функции
- •Шаблоны, которые используют несколько типов
- •Глава 5. Функции для работы с символьными строками
- •Основные стандартные строковые функции
- •Функция sprintf()
- •Функция strcpy()
- •Функция strcmp()
- •Функция strcmpi()
- •Функция strcat()
- •Функция strlen()
- •Пример программы проверки функций
- •Новые типы переменных
- •Константы
- •Новые операции
- •Преобразование типов данных
- •Побитовые логические операции
- •Операции и выражения присваивания
- •Условное выражение
- •Операторы и блоки
- •Конструкция if-else
- •Конструкция else-if
- •Переключатель switch
- •Уточнение по работе оператора for
- •Оператор continue
- •Оператор goto и метки
- •Глава 7. Работа с указателями и структурами данных
- •Указатель
- •Указатели и массивы
- •Операции над указателями
- •Указатели и аргументы функций
- •Указатели символов и функций
- •Передача в качестве аргумента функции массивов размерности больше единицы
- •Массивы указателей
- •Указатели на функции
- •Структуры. Объявление структур
- •Обращение к элементам структур
- •Структуры и функции
- •Программы со структурами
- •Функция возвращает структуру
- •Функция возвращает указатель на структуру
- •Программа упрощенного расчета заработной платы одному работнику
- •Рекурсия в структурах
- •Битовые поля в структурах
- •Категории памяти
- •Глава 8. Классы в С++. Объектно-ориентированное программирование
- •Классы
- •Принципы построения классов
- •Инкапсуляция
- •Наследование
- •Полиморфизм
- •Примеры создания классов
- •Пример 1
- •Пример 2
- •Пример 3
- •Конструктор класса
- •Деструктор класса
- •Классы и структуры в среде CLR
- •Классы и структуры
- •Абстрактные классы
- •Статические функции и элементы данных
- •Частные и общие данные. Интерфейсные функции
- •Использование оператора глобального разрешения для элементов класса
- •Глава 9. Ввод и вывод в языках С и С++
- •Ввод и вывод в С
- •Ввод/вывод файлов
- •Основные функции для работы с файлами
- •Стандартный ввод/вывод
- •Функции стандартного ввода/вывода
- •Ввод/вывод в С++
- •Общие положения
- •Ввод/вывод с использованием разных классов
- •Пространства имен
- •Работа с классом fstream
- •Работа с классом ofstream
- •Работа с классом ifstream
- •Работа с бинарным файлом
- •Стандартный ввод/вывод в С++
- •Общие положения
- •Стандартный вывод cout
- •Стандартный ввод cin
- •Глава 10. Продолжение изучения среды Visual C++
- •Создание проекта
- •Некоторые файлы проекта
- •Окно сведений об объекте
- •Вкладка Events
- •Вкладка Property Pages
- •Работа с окном сведений об объекте
- •Контекстное меню редактора кода
- •Суфлер кода (подсказчик)
- •Настройка редактора кода
- •Управление окнами редактора
- •Изменение шрифта и цвета
- •Начало редактирования кода программного модуля
- •Компоненты среды программирования VC++
- •Класс Form
- •Дизайнер форм
- •Помещение компонента в форму
- •Другие действия с дизайнером форм
- •Контекстное меню формы
- •Добавление новых форм к проекту
- •Организация работы с множеством форм
- •Вызов формы на выполнение
- •Cвойства формы
- •События формы
- •Некоторые методы формы
- •Рисование графиков в форме
- •Глава 11. Компоненты, создающие интерфейс между пользователем и приложением
- •Пространство имен System
- •Работа с переменными некоторых типов
- •Компонент Button
- •Свойства Button
- •События Button
- •Методы Button
- •Компонент Panel
- •Некоторые свойства Panel
- •Некоторые события Panel
- •Компонент Label
- •Некоторые свойства Label
- •События Label
- •Компонент TextBox
- •Некоторые свойства TextBox
- •События TextBox
- •Некоторые методы TextBox
- •Компонент MenuStrip
- •Некоторые свойства MenuStrip
- •События MenuStrip
- •Компонент ContextMenuStrip
- •Компонент ListView
- •Некоторые свойства ListView
- •События ListView
- •Компонент WebBrowser
- •Компонент ListBox
- •Как работать с ListBox
- •Свойства ListBox
- •Как использовать ListBox
- •Как формировать список строк
- •Компонент СomboBox
- •Свойства ComboBox
- •События ComboBox
- •Некоторые методы ComboBox
- •Примеры использования ComboBox
- •Пример 1
- •Пример 2
- •Пример 3
- •Компонент MaskedTextBox
- •Свойства MaskedTextBox
- •Компонент СheckedListBox
- •Пример: домашний телефонный справочник
- •Компоненты CheckBox и RadioButton
- •Компонент GroupBox
- •Компонент LinkLabel
- •Компонент PictureBox
- •Некоторые свойства компонента PictureBox
- •Компонент DateTimePicker
- •Форматные строки даты и времени
- •Стандартное и пользовательское форматирование
- •Некоторые сведения о работе с датами
- •Компонент TabControl
- •Как задавать страницы
- •Некоторые методы TabControl
- •Некоторые свойства страницы TabPage
- •Как защитить страницу от неавторизованного доступа
- •Задача регистрации пользователя в приложении
- •Компонент Timer
- •Компонент ProgressBar
- •Компонент OpenFileDialog
- •Компонент SaveFileDialog
- •Компонент ColorDialog
- •Компонент FontDialog
- •Компонент PrintDialog
- •Компонент ToolStrip
- •Некоторые свойства ToolStrip
- •Использование ToolStrip
- •Глава 12. Работа с наборами данных. Общие сведения о базах данных
- •Проектирование баз данных
- •Модель базы данных
- •Структура проектирования базы данных
- •Идентификация сущностей и атрибутов
- •Проектирование таблиц
- •Определение неповторяющихся атрибутов
- •Набор правил при разработке таблицы
- •Определение ограничений на целостность данных
- •Принудительное обеспечение целостности данных
- •Выбор индексов
- •Язык SQL
- •Примеры оператора SELECT
- •Наборы данных (компонент DataSet)
- •Общая технология организации работы с базой данных в приложении
- •Пример работы с базой данных
- •Глава 13. Управление исключительными ситуациями
- •Операторы try, catch и throw
- •Пример 1
- •Пример 2
- •Классы типов исключений
- •Пример 3
- •Функции, выдающие исключения
- •Пример 1. Перевод строки String ^ в ASCII-строку
- •Пример 2. Перевод ASCII-строки в строку String ^
- •Пример 3. Преобразование строки String ^ в строку wchar_t
- •Пример 4. Преобразование строки wchar_t в строку String ^
- •Пример 5. Маршалинг native-структуры
- •Пример 6. Работа с массивом элементов native-структуры в managed-функции
- •Пример 7. Доступ к символам в классе System::String
- •Пример 10. Преобразование String в string
- •Пример 11. Преобразование string-строки в String-строку
- •Пример 12. Объявление дескрипторов в native-типах
- •Пример 13. Работа с дескриптором в native-функции
- •Предметный указатель
Глава 7. Работа с указателями и структурами данных |
117 |
Передача в качестве аргумента функции массивов размерности больше единицы
До сих пор мы передавали в качестве аргумента функции только одномерный массив. Можно передавать и массивы большей размерности. Если, например, двумерный массив передается в качестве аргумента функции, то его описание, как аргумента функции, может быть следующим:
int m[2][13]; int m[][13];
Здесь m указывает на начало массива, поэтому компилятору достаточно знать только количество столбцов массива и начало его первого элемента.
Другой вариант описания:
int (*m)[13];
Здесь m указывает на начало массива.
Массивы указателей
Мы видели, что с помощью массива, объявленного, например, как char M[n][m], можно задавать множество символьных строк постоянной длины. Иначе и не задать, потому что компилятор не сможет найти заданный элемент массива. Однако в жизни чаще всего приходится работать со строками переменной длины. Тогда жесткая конструкция двумерного массива для их хранения не подойдет.
Для решения этой проблемы существует конструкция, называемая массивом указателей. Создается одномерный массив, элементами которого служат указатели на заданный тип данных. Например, массив char *s[10]; — это десять указателей (s[0],s[1],...,s[9]), каждый из них указывает на строку, которая может быть переменной длины.
Такой массив формируется так: в некоторой памяти размещается первая строка, ее адрес заносится в s[0]. Затем размещается вторая строка, ее адрес заносится в s[1] и т. д. Чтобы обратиться к элементам такого массива, нужно воспользоваться определением указателя. Обратиться к нулевому элементу нулевой строки следует как *s[0], к первому элементу той же строки как *s[0]++ и т. д. К нулевому элементу первой строки нужно обратиться как *s[1], к ее первому элементу как *s[1]++ и т. д.
Инициализация массива указателей на строки символов, например, char *s[3]; будет выглядеть так:
char *s[3]={"Первая строка символов", "Вторая строка символов", "Третья строка символов"};
В чем же различие между записями, например, int n[10][20] и int *b[10]?
Под первый вариант компилятор выделяет 200 единиц памяти. И поиск элемента этого массива производится путем вычисления обычных прямоугольных индексов.
118 |
Часть I. Изучение языка С/С++ |
|
|
При втором варианте (если предположить, что и там строки содержат по 20 элементов) под них также будет выделено 200 единиц памяти, но еще понадобится память для хранения десяти указателей. То есть памяти при втором варианте размещения данных требуется больше. Но это неудобство перекрывается тем, что в таких конструкциях можно хранить строки переменной длины, и что доступ к таким строкам происходит напрямую — по их адресам, без вычисления индексов массивов.
Указатели на функции
В языке С возможно определять указатели на функции и, следовательно, обрабатывать указатели, передавать их в качестве аргумента другим функциям и т. д. При объявлении указатель на функцию записывается в виде:
<Тип возвращаемого функцией значения> (*имя функции) (список параметров)
Например:
int (*comp)(char s1,char s2);
Это указатель на функцию comp(s1,s2), которая возвращает результат типа int. Если мы подействуем операцией разыменования (*) на этот указатель (по определению указателя записав воздействие в виде (*comp)(s1,s2)), то функция comp(s1,s2) выполнится и возвратит некое целое число.
Ранее мы видели, что имена массивов можно передавать в качестве аргументов функции. Теперь, поскольку есть указатели на функции, функции можно передавать в качестве аргументов другим функциям. В таких функциях их аргументы-
функции описываются как указатели на функции, а передача функций в качестве аргументов происходит указанием имени самой функции. Все остальное улаживает компилятор. То есть с функциями, при передаче их в качестве аргументов другим функциям, происходит то же, что и с массивами: их имена считаются внешними переменными. Приведем пример функции gener(), которая в качестве своих параметров имеет две функции: ввода строки символов и подсчета количества ненулевых битов в целом числе (листинг 7.5).
Листинг 7.5
// 7.5_2011.cpp
#include "stdafx.h"
#include <stdio.h> //для getchar(),putchar()
#include <conio.h>
#include <stdlib.h> //для atoi() using namespace System;
#define eof '?' #define maxline 1000
Глава 7. Работа с указателями и структурами данных |
119 |
|
//--- Функция подсчета количества битов в целом числе |
|
|
int bitcount(unsigned int n) |
|
|
{ |
|
|
int b; |
|
|
for(b=0; n != 0; n>>=1) |
|
|
if(n & 01) //01 — восьмеричная единица |
|
|
b++; |
|
|
return(b); |
|
|
} |
|
|
//-------Ввод строки с клавиатуры |
|
|
int getline(char s[],int lim) |
|
|
{ |
|
|
int c,i; |
|
|
for(i=0; i<lim-1 && (c=getchar()) != eof && c != '\n'; i++) |
|
|
s[i]=c; |
|
|
s[i]='\0'; |
|
|
i++; |
//для учета количества |
|
return(i); |
|
|
} |
|
|
//Функция вводит число n с клавиатуры //и подсчитывает количество единиц в нем
int gener(int (*getline)(char s[],int lim),int (*bitcount)(unsigned int n))
{
char s[maxline]; int lim=100;
printf("Enter any number >\n"); (*getline)(s,lim);
unsigned int n=atoi(s); n=(*bitcount)(n); return(n);
}
//-------------------------------------------------------------
int main()
{
int n=gener(getline,bitcount);
printf("The amount of ones in the input n=%o\n",n); _getch();
return 0;
}
Мы уже знакомы с функциями getline() и bitcount() (последнюю составляли, когда изучали операции сдвига — она подсчитывает в целом числе без знака количество единиц (ненулевых битов)).
120 |
Часть I. Изучение языка С/С++ |
|
|
Рассмотрим вызывающую функцию gener(). Мы видим, что оба ее аргумента описаны как указатели на функции: первый — на функцию getline(), второй — на bitcount(). Затем идет выполнение первой переданной в качестве аргумента функции. Чтобы заставить выполниться функцию, находящуюся по адресу, который содержится в указателе getline, надо подействовать на него операцией разыменования (по определению указателя).
Получим (*getline)(s,lim);
Функция getline() выполнится и результатом ее работы станет введенное в строку s число, которое переводится в беззнаковое n c помощью функции atoi(). После этого выполнится функция bitcount(), тоже описанная как указатель. Результат ее работы и возвращается в качестве результата функции gener(). Результат расчета показан на рис. 7.5.
Рис. 7.5. Результат расчета программы листинга 7.5
Структуры. Объявление структур
Структуры — это такие конструкции языка С, которые объединяют в себе данные разных типов, в том числе и подструктуры (такие же структуры, но являющиеся членами главной структуры). Эти конструкции полезны тем, что во многих ситуациях позволяют группировать связанные данные таким образом, что с ними можно работать как с единым целым. Как объявляется структура, покажем на примере объявления данных некоторого человека:
struct man
{
char name[80]; //имя
char phone_number[80]; //телефон int age; //возраст
int height; //рост
};
Так задается шаблон будущего экземпляра структуры. Здесь man — имя шаблона. То, что находится в теле, ограниченном фигурными скобками, — это члены струк- туры-шаблона (под такое объявление компилятор память не выделяет). На основе такого шаблона создается экземпляр структуры, под который память уже выделяется и с которым можно работать в программе. Чтобы начинающему изучать С было более понятно, скажем, что объявленный шаблон — это тип "структура". А имея
Глава 7. Работа с указателями и структурами данных |
121 |
такой тип, станем объявлять данные этого типа. Точно так же, как имея, например, тип int, начинаем объявлять данные типа int.
Экземпляры структуры создаются несколькими путями: по шаблону man:
struct man friends[100],others;
Здесь созданы два экземпляра структуры: один — это массив структур (каждый элемент такого массива представляет собой структуру шаблона man. Можно сказать так: friends — это переменная типа man), другой — обычный экземпляр по шаблону man. В языке С++ ключевое слово struct можно опускать, т. е. в С++ уже пришли к аналогии с простыми типами данных: там экземпляр структуры уже можно объявить так:
man friends[100],others;
Видите сходство с объявлением простых переменных? И friends и others объявлены как переменные типа man;
при объявлении шаблона:
struct man
{
char name[80];
char phone_number[80]; int age;
int height; }others;
Здесь создан один экземпляр структуры — others;
с помощью квалификатора типа typedef, который изменяет имя шаблона и позволяет воспользоваться новым именем в качестве типа данных. Этот квалификатор позволяет вводить в объявления имена-синонимы, более удобные в использовании в программе. Например, можно записать объявление некой переменной в виде typedef int step; и далее в программе при объявлении какой-то переменной писать вместо int ее синоним step: step aa;. Компилятор потом все вернет на свои места. По этому же принципу можно сократить работу со структурой, объявив, например,
typedef struct
{
char phone_number[80]; int age;
int height; }aa;
То есть заменили всю структуру на один тип aa.
Теперь можно писать: aa d1,d2[20],*p;. Здесь объявлено три переменных типа aa: экземпляр d1 структуры шаблона man, массив структур d2[20] и р — указатель на структуру.