Будь умным!


У вас вопросы?
У нас ответы:) SamZan.net

Лекции по дисциплине Информатики и программирование Автор ' Шульга Т

Работа добавлена на сайт samzan.net:

Поможем написать учебную работу

Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.

Предоплата всего

от 25%

Подписываем

договор

Выберите тип работы:

Скидка 25% при заказе до 24.11.2024

16

Лекции по дисциплине «Информатики и программирование»

Автор – Шульга Т.Э.

Продолжение темы 4 (Концепция типа данных)

В языках программирования существует множество различных типов данных. На предыдущих лекциях нами были рассмотрены только основные типы данных языка программирования С. Для того, что чтобы разобраться в многообразии типов данных вводят различные классификации. Рассмотрим две такие классификации.

Первая из них  - классификация по строению элемента. В соответствии с ней все типы модно разделить на скалярные (простые), которые не имеют внутренней структуры и структурированные, которые состоят из элементов других типов. Иными словами, cскалярный (простой) тип данных позволяют хранить только одно значение, а структурированный тип данных позволяют хранить совокупности значений. Все рассмотренные в предыдущей теме типы данных являются скалярными. В общем случае  к скалярным типам относятся числовые и символьные типы, указатели, перечисления. К структурированным типам относят, например, массивы, структуры, классы.

Вторая классификация в качестве критерия использует способ создания типа данных. В соответствии с этим критерием, все типы данных делятся на встроенные (стандартные, определенные в стандарте языка) и определяемые программистом. К встроенным типам обычно относят числовые и символьные типы данных, логический тип. К типам, определяемым программистом, относят, например, перечисления, структуры, классы.

В данной лекции рассмотрим такие типы данных как указатели, ссылки, перечисления, массивы, строки.

Указатели

Указатели – это переменные, значениями которых служат адреса участков памяти, выделенных для объектов конкретных типов. Различают три вида указателей – указатели на объекты, на функции и на void. Кроме того, различают указатели-переменные и указатели-константы. В простейшем случае определение указателя-переменной на некоторый объект имеет вид

тип *[const] имя [инициал_выр];

где звездочка относится непосредственно к имени. Например,

char *t1, *t2, t3; // t1, t2 -неинициализированные указатели на объекты типа int (то есть в переменных t1, t2 может храниться адрес объекта типа int), a t3 – переменная типа int;

const int *t1; указатель на константу целого типа.

В качестве инициализирующего выражения указателя должно использовать константное выражение, частными случаями которого являются

  1. явно заданный адрес участка памяти,
    char *p1= (char *) 0xb8000000; // обратите внимание на необходимость преобразования числового значения к типу указателя (char *).
  2. пустое значение (NULL),
    char *p2 =NULL; // нулевой указатель на объект типа char. Если значение константного выражения равно нулю, то это нулевое значение преобразуется к пустому (иначе нулевому, NULL) указателю. Нулевой указатель отличен от указателя на любой объект.
  3. выражение, позволяющее получить адрес объекта с помощью операции ‘&’,
    char c = 'a';
    char* const p3 = &c;//указатель в p хранится адрес c
  4. указатель, уже имеющий значение,
    char *p4=p3; // в p4 также хранится адрес c.

Кроме того, инициализировать указатель можно с помощью операции динамического выделения участка памяти функцией malloc (из библиотеки stdlib.h). Например,

char *p5= maloc(1)  или char *p5= maloc(sizeof(char)); //выделили память для перемененной типа char и связали указатель p с эти участком памяти.

Таким образ выделенная память должна быть освобождена с помощью функции free. В противном случае одна будет занята до перезагрузки операционной системы (Это проблема называется проблемой «динамического мусора»). Например, free(p5);

Основная операция над указателем – разыменование, унарная операция ‘*’ (получение значения через указатель). Эта операция также называется косвенным обращением или обращением по адресу. Например,

char d=*p3;// значением переменной c2 будет значение  того участка памяти, с которым связан указатель p, то есть c=d= ‘a’.

С помощью операции разыменования инициализированного указателя можно не только получать, но и изменять содержимое участка памяти, с которым связан указатель. Например,

*p= ‘b’; // значением переменной с и d стал символ ‘b’.

Разыменование нулевого указателя приводит к ошибки времени выполнения, так как данная область памяти недоступна. Разыменование  неинициализированного указателя приведет либо к ошибке времени выполнения, либо к получению случайных данных из памяти. Поэтому рекомендуется всегда инициализировать указатель при описании, а перед разыменованием проверять его на NULL.

Над указателями-переменными можно также осуществлять операции присваивания, сложение с константой, вычитание, --, ++, сравнение, приведение типов.

Если указатель описан со спецификатором const (то есть является константой-указателем), то он должен быть инициирован  и  его значения нельзя будет изменить с помощью приведенных выше операций. Например,

char * const p6=p5;

Указатель на void применяется в тех случаях, когда конкретный тип объекта, адрес которого следует хранить, не определен. Таким указателям можно присвоить значение указателя любого типа, а также сравнивать его с любыми указателями.

Ссылки

Ссылка представляет собой синоним имени, уже существующего объекта, и поэтому не занимает место в памяти (в отличии от указателя). Формат описания:

тип & имя инициализатор;

Наличие инициализатора обязательно. После инициализации ссылке не может быть присвоено другое значение. Например,

int a=10;

int& a1=a;

printf(“%d%d”,a,a1);

a1+=2;

printf(“%d%d”,a,a1);

Значением ссылки является адрес объекта, на который указывает ссылка, и, по сути ссылка представляет указатель, который не надо разыменовывать. В основном ссылки используются при работе с функциями.

Перечисления (перечислимый тип)

Перечислимый тип по существу описывает целые константы (типа int), которым приписаны уникальные и удобные для использования имена.

Формат описания:

emun [имя типа] {список констант}

где константы могут быть инициализированы обычным образом.

Например,

enum digit {one=1,two,three};

Здесь one, two, three – произвольным образом выбранные программистом идентификаторы для обозначения констант 1,2,3. После такого определения в программе наряду, например, с константой 1 можно использовать ее обозначение one. Фактически такая запись равносильно записи

const int one=1;

const int two=2;

const int three=3;

Обычно перечислимый тип используется для задания числовых рядов или стандартных рядов, таких как месяцы, дни недели.

Если в определении перечислимых констант опустить знаки “=” и не указывать числовых значений, то они будут присваиваться идентификаторам по умолчанию следующим образом: самый левый в фигурных скобках идентификатор получит значение 0, а каждый последующий увеличивается на 1. Имена перечислимых констант должны быть уникальными, а их значения могут совпадать.

Имя типа указывают, если требуется вводить в программе переменные этого типа. Например

digit d1,d2;

Компилятор обычно обеспечивает, чтобы эти переменные принимали значения только из списка констант.

Массивы

Массив - самая распространенная структура данных, реализованная практически во всех языках программирования. Массив – это именованная последовательность однотипных элементов, расположенных в памяти компьютера последовательно. Тип элементов массива называют базовым. К любому элементу массива можно обращаться произвольным образом, так как он имеет определенный номер, называемый индексом.

Описание массива в общем случае имеет формат:

[класс памяти] [const] тип имя [константное выражение]={список инициализирующих элементов};

Константное выражение представляет собой количество элементов массива (размерность массива). Если массив объявлен без инициализирующего списка, то задание размерности массива обязательно. Например,

int a[10]; - массив из 10 целых чисел

int n=10; int  a[n]; - недопустимо, так как n – не константа

int a[]; - недопустимо, так как нет ни размерности ни инициализирующего списка.

Предпочтительнее задавать размерность массива с помощью именованных констант. Например,

const int n=10;

int mas[n];

Когда массив объявлен без указания размера, но при этом инициализирован списком, его размер вычисляется путем подсчета числа элементов этого списка. Например

int a []={1,2,3,4};//размерность массива равна 4

Явная инициализация массива разрешена только при его определении и возможна двумя способами: либо с указанием размера массива в квадратных скобках, либо без его явного указания, например,

int а[6]={1,2,3,4};//массив из 6 целых чисел с инициализацией первых четырех, остальные будут обнулены.

char str1[]={‘a’, ‘b’, ‘c’};// массив из 3 элементов типа char

Число элементов в инициализирующем списке должно быть меньше и равно указанной размерности массива, то есть запись int a[3]={1,2,3,4}; недопустима.

Доступ к элементам массива осуществляется с помощью комбинации имя массива + индекс элемента  следующими двумя способами.

  1. С помощью записи имя_массива[индекс элемента]. То есть, чтобы обратится к i- тому элементу массива а, используют запись а[i], при этом первый элемент массива имеет индекс 0.
  2. С помощью записи *(имя_массива+индекс элемента) Важно понимать. что имя массива является указателем-константой на его первый элемент. То есть, если описан массив int a [n], то для обращения к его i-ому элементу наряду с записью a[i], можно использовать запись *(a+i).

Работа с элементами массива организовывается обычно в цикле.

Для ввода и вывода элементов массива  а можно использовать записи

scanf(“%d%d%d”, &a[0], &a[1], &a[3]);

printf (“%d%d%d”, a[0],a[1],a[3]);

соответственно, при условии, что количество элементов точно известно и невелико. На практике так поступают редко.

При выполнении команды printf(“%d”,a); на экране появится адрес памяти, по которому расположен первый элемент массива a. Комадна scanf("%d",a) считает данные с клавиатуры в первый элемент  массива.

Исключение составляют только массивы символов (char), для которых функции printf и scanf работают по-другому.

Например, пусть  описан массив

char s[255]=”Hello”;/*обратите внимание, что массив типа char допустимо инициализировать не только списком элементов в скобках {}, но и строковой константой*/

printf(“%s”,s); //на экран выведется, не адрес памяти, а вся строка

scanf("%s",s); // с клавиатуры считаются все символы до первого пробельного разделителя.

Функция malloc, используемая для инициализации указателей, позволяет определять массив еще одним способом (это так называемый динамический массив):

int k;

scanf(“%d”, &k);

int *a=malloc(k*sizeof(int);

Память, зарезервированная под динамический массив, должна освобождаться явным образом функцией  free, например free(a);

Многомерные массивы описываются как массивы массивов, например,

int a2[3][2] //массив из 3 массивов, содержащих по 2 целых элемента.

Для обращения к элементу двумерного массива используется два индекса, например, a2[i][j]. Для работы с двумерными массивами используется конструкция вложенных циклов.

Задание для самостоятельной работы! Придумать, как двумерный массив задать динамически.


Строки

В языке С тип данных «строка» не определен, но определено понятие С-строка. С-строка – это массив символов, заканчивающийся ноль-симолом. Ноль-симовол – это символ с кодом, равным нулю, что записывается в виде esp-последовательности ‘\0’.

В С строка может быть описана двумя способами:

  1.  Как массив символов

Например,

char str1[]= “adc”; //массив из 4 элементов типа char, элемент str2[3]= ‘\0’ – признак конца строки.

  1.  Как указатель на строковую константу

Например,

char *str2= “abc”; // указатель на строковую константу

Для строк не определено специальных операций, они обрабатываются как обычные массивы. Однако в отличии от массивов других типов, можно считать все символы строки с клавиатуры можно с помощью одной функции scanf (“%s”, имя_символьного_массива). Следует помнить, что в этом случае считается только символы по первого пробельного разделителя.  Кроме того, всю строку можно вывести на экран с помощью одной функции printf (“%s”, имя_символьного массива).

Например

char s[]="Hello";

printf("%s",s);// на экран выведется слово «Hello», а  для массивов других типов в данном случае выведется только адрес памяти первого элемента.

scanf("%s",&s);//

// считывается строка для первого пробельного разделителя, для массивов других типов считается первый элемент.

Если на клавиатуре набрать строку «мама мыла раму», то в массив запишется только слово «мама», то есть в массиве будет 5 элементов со значениями ‘м’, ‘а’, ‘м’, ‘а’, ‘\0’.

printf("%s",s);//на экран выведется вся строка «мама»,

Кроме того строку можно считать с помощью функции gets(имя_символьного массива); Однако, она не контролирует выход за пределы массива.

При выводе символьного массива с помощью функции printf  из памяти выводятся подряд все символы, начиная с первого и до тех пор, пока не встретится символ ‘\0’. Поэтому, если символьный массив инициализирован списком (а не строковой константой) или заполнятся в цикле ответственность за то, чтобы последний символ был символом конца строки, ложится на плечи программиста.

Например,

char s[]={‘m’, ‘a’, ‘m’};

printf("%s",s);///на экран выведется mamЁ@kj^^    и т.п.

Существует функции стандартной библиотеки, которые позволяют копировать, сравнивать, объединять строки, выделять подстроки, определять длину строки, считывать строки с клавиатуры и файла. (Они описаны в заголовочных файлах stdio.h, stdlib.h, string.h)

Например,

#include <stdio.h>

#include <string.h>

main ()

{

const int n1=20;

int n2=20;

char str1[n1];

char *str2=malloc (n2);

gets(str1);//считываем строку

printf("Первая строка %s\n",str1);

scanf (“%s”,str2);//считываем строку до первого пробельного разделителя

 printf("Вторая строка %s\n",str2);

 printf("Длина строк: %d %d\n", strlen(s1), strlen(s2));

 if(!strcmp(s1, s2)) printf("Строки равны\n");

 strcat(s1, s2);// объединяем строки

 printf("Объединенная строка: %s\n", s1);

}




1. Амплитудно-частотные характеристики и настройка связанных контуров
2. Н Бердяев Новое средневековье
3. Политика социальноэкономического развития Беларуси 5
4. начала XX веков. истоки структура особенности СУВОРОВ Алексей Иванович ~ кандидат исторических наук д
5. Лекция 8 54 Влияние флуктуаций на ВАХ If
6. Агрономия Составитель Алексеев В
7. Общее положение о крестьянах вышедших из крепостной зависимости содержал главные условия крестьянской
8. Доклад- Сущность, формы и функции исторического сознания
9. Российская урбанизация 1860-1914 годов в трудах отечественных историков
10. А Наименование на 1 января 2011 года на 1 января 2012 года
11. Исследование устойчивости разомкнутой системы электропривода ТПН-АД
12. х72полосные коаксиальные200 Вт MYSTERYMF 6
13. Под национализацией понимается принудительное обращение имущества находящегося в собственности гра
14. зелёные круги в клетках ядра в некоторых из ядер в свою очередь заметны ядрышки светлозелёные
15. Тема 15 Оценка стоимости организации 1.
16. Газоснабжение жилого района
17. ВИТЕБСКИЙ ОБЛАСТНОЙ УЧЕБНОМЕТОДИЧЕСКИЙ ЦЕНТР ФИЗИЧЕСКОГО ВОСПИТАНИЯ НАСЕЛЕНИЯ
18. ситуация с ее внешними долгами как никогда серьезна
19. ЖКУтепова МА Джемпер женский Арт-60169 Странапроизводства; КитайПекин Состав;хлопок60
20. Тверская область Член СФР с 1998 года