Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Рекомендуемая структура программы



Программы на языках C и Basic в общем случае состоят из нескольких модулей, структура каждого из них строится по общим правилам.

Структура модуля на языке Basic

инструкции Imports

инструкция Module

определения глобальных данных

Sub Main ()

локальные определения и описания

выполняемые инструкции

End Sub

тексты процедур и функций

End Module

Структура модуля на языке C

директивы препроцессора (#define, #include )

описания и определения внешних объектов

int main( ){

локальные определения и описания

выполняемые инструкции

}

тексты функций

Рекомендуемая структура не вполне корректна по следующим причинам:

- директивы препроцессора могут встречаться в любом месте файла, единственное ограничение в том, что они должны предшествовать определяемым константам;

- перед текстом функции main () могут быть определения других функций;

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

Вопросы для самопроверки и контроля

Вопросы для самопроверки

1. Могут ли исполняемые инструкции записываться вне тела процедур?

2. Может ли в одной области видимости исполняемая инструкция предшествовать декларации?

3. Отличается ли время жизни для объектов static и extern?

4. Объявление объекта с ключевым словом extern это определение или описание?

5. Что произойдет, если число инициаторов будет больше числа элементов массива?

Контрольные вопросы

1. В чем отличие применения ключевого слова static в языках C и Basic?

2. Укажите различия в действии инструкции Public и атрибута extern?

3. Чем инициируются определяемые объекты в языке Basic?

4. Что определяет инструкция Private?

 

УКАЗАТЕЛИ, МАССИВЫ, СТРОКИ

Материал этого раздела посвящен указателям, связи указателей с массивами, выделению памяти по указанию программиста (так называемым динамическим объектам) и строкам. Следовательно, большая его часть относится к языку C, поскольку в языке Basic нет понятия указателя. Приемы работы со строками включены в этот раздел в связи с тем, что в языке C нет такого типа данных и все манипуляции со строковыми данными осуществляются с помощью библиотечных функций, большинство из которых в качестве аргументов и возвращаемого значения используют данные типа char * (указатель на тип char ). Представляется логичным рассмотреть в соответствующем подразделе средства манипулирования со строками языка Basic, которые будут специально выделены.

Указатели

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

Определение указателей

Признаком указателя при объявлении переменных является символ '*'. Указатели могут быть на любой тип данных и даже на функцию, которая к данным не относится.

Пример.

char *s, *x;

double *t, *p;

complex *y; // Тип данных пользователя

Задание значений

Задать значение указателю можно следующими способами:

· p=& l; // Задание адреса объекта программы

· t=p; // Присваивание значения другого указателя

· p=NULL; // Символическая константа NULL, определенная в

//файле stdio.h, используется для задания значения,

// не указывающего ни на 1 объект программы

· scanf(" % p ", & q); // Ввод c клавиатуры. Спецификация p

· pt=( double *)0777000; // Ссылка на фиксированный адрес

Последние 2 способа используются редко.

Вывод значений

Используется редко.

Пример.

printf(" Адрес структуры=% p \n", ptr); // Адрес структуры=FF00

Указатели и массивы

Между указателями и массивами существует тесная связь. Любое действие, выполняемое индексированием массива, может быть реализовано с помощью указателей, причем последний вариант более быстр и объектный код более компактен, однако такая реализация требует навыка и воспринимается хуже.

Если имеется определение вида short a[10], то упоминание имени a в программе означает ссылку (адрес) на элемент массива a[0], т.е. на начальный адрес массива. Пусть имеем определение short *pa; тогда запись pa=& a[0] эквивалентна записи pa=a.

С указателями можно выполнять арифметические действия, лишь бы они имели смысл.

Пример.

short a[10], *pa;

pa=a;

Выражение pa+5 определяет адрес 5-го элемента массива a, т.е. это выражение задает смещение в 10 байтов от начала массива; выражение pa+i - адрес i-го элемента массива a. Отсюда следует, что запись *(pa+i) эквивалентна записи *(a+i), а она эквивалентна в свою очередь записи a[ i ]. Аналогично b[ i ][ j ] эквивалентно *(*(b+i)+ j).

Вывод. Любое обращение к элементу массива можно записать как ссылку и смещение относительно начального адреса массива.

Между использованием массивов и указателей есть следующие отличия:

- определение массива вызывает выделение памяти под все элементы массива, а определение указателя – выделение памяти только под него;

- имя массива является указателем – константой, т.е. его значение изменить нельзя, а значение указателя можно.

Пример. Сортировка массива с помощью индексирования и указателей.


void sort( short n, double zap[ ]){

double buf;

short i, j, min_ind;

for (i=0; i< n-1; i++){

buf=zap[ i ];

min_ind=i;

for (j=i+1; j< n; j++){

if (buf> zap[ j ]){

buf=zap[ j ];

min_ind=j;

}

}

void sort( short n, double *zap){

double buf;

short i, j, min_ind;

for (i=0; i< n-1; i++){

buf=*(zap + i);

min_ind=i;

for (j=i+1; j< n; j++){

if (buf> *(zap + j)){

buf=*(zap + j);

min_ind=j;

}

}


zap[min_ind]=zap[ i ];

zap[ i ]=buf;

}

} // End sort

*(zap + min_ind)=*(zap + i);

*(zap + i)=buf;

}

} // End sort


Для многомерных массивов запись x[ i ] означает адрес i-го подмассива (сечения). При n=2 запись x[ i ] эквивалентна записи & x[i][0].

Пример применения.

double x[10][10];

................

sort(10, x[ i ]); // Обращение к функции сортировки элементов i-й строки

Работа со строками

Здесь будут рассмотрены средства манипулирования со строковыми данными как в языке C, так и в языке Basic. Эти средства группируются по функциональному признаку с тем, чтобы получить представление об общих чертах и отличиях в их реализации на каждом языке. Наряду с новыми средствами будут приведены и описанные ранее. Цель такого изложения материала заключается в том, чтобы свести в одном разделе практически все аспекты обработки символьных данных для консольных приложений.

Литералы

Правило записи строковых литералов в языках C и Basic одинаково:

строковый литерал: = " < текст> "

Пример.

" Это строковый литерал"

В языке Basic литерал типа string относится к виду строк переменной длины и занимает в памяти (10 + длина строки) байтов.

В языке C любой строковый литерал есть массив символов, заканчивающийся символом '\0', который добавляет транслятор, т.е. его длина в памяти на 1 символ (байт) больше числа символов между кавычками.

Пример.

" Это строка! " (11 знаков) à в памяти будет: Это строка! \0 (12 знаков)

Переменные


Basic

Тип данных string.

Объявление:

< имя> As String

C

Типа данных string нет.

Вместо строковых переменных используются массивы типа char. Объявление:

char < имя> [< длина> ];



Операторы и функции


Basic

C



Ввод - вывод



Ввод строки в окно InputBox(поясняющий текст[, заголовок окна]

[, значение по умолчанию][, xнач] [, yнач]).

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

Аргументы:

- если заголовок окна опущен, то в окно помещается имя приложения;

- значение по умолчанию – значение, появляющееся в поле ввода; если пользователь согласен с этим значением, то, не вводя значение с клавиатуры, нужно щелкнуть по кнопке ОК;

- xнач, yнач – координаты левого верхнего угла окна; если xнач опущено, то окно центрируется по горизонтали; если yнач опущено, то окно располагается примерно на уровне 1/3 от верха экрана.

Пример. InputBox(" Число людей в кругу: " )

Поясняющий текст: Число людей в кругу.

Заголовок окна: Flavii.

Файл прототипов stdio.h.

Ввод с клавиатуры:

- функция scanf(спецификация % s );

- функция gets( char* ).

Введенное значение заносится в символьный массив. Обе функции добавляют конечный символ '\0'.

Можно заполнять символьный массив с клавиатуры в цикле с помощью функции getchar( ). В этом случае, конечный нуль не добавляется.

Пример. Поэлементное присваивание.

char str1[20], str2[20];

...................................

gets(str1);

for (i=0; str2[ i ]=str1[ i ]; i++);

Вывод на экран:

- функция printf (спецификация % s );

- функция puts ( char* ).

Также в цикле можно выводить строки с помощью функции putchar( int ).


Вывод строки в окноMsgBox(сообщение[, кнопки][, заголовок]).

Возвращаемое значение: код нажатой кнопки. Используется для организации диалога. Изучить самостоятельно.

Пример. MsgBox(" Остался жив №" & nomer)

Аргументы:

 

- кнопки – целое выражение, кодирующее число и названия выводимых в окно кнопок; если опущено, выводится одна кнопка ОК;

- заголовок – см.функцию InputBox.

Консольный ввод: ReadLine( )

Консольный вывод: {Write | WriteLine}(< управляющая строка> [, < список-данных> ])



Конкатенация (сцепление)

 


Оператор &


Файл прототипов для после-дующих функций string.h.

char* strcat(левая строка, правая строка)

Результат – левая строка.


Копирование (присваивание)


Оператор =

char* strcpy(копия, оригинал)

 


 


Сравнение


Оператор =

Пример.

Dim str1 As string, str2 As String

str1=" Привет " : str2=" семье! "

str1 & str2 à " Привет семье! "

If str1 = str2 Then ' Результатà False

Есть 2 режима сравнения строк, которые задаются инструкцией вида:

Option Compare < режим> либо в меню среды:

Project (Проект)à Properties (Свойства) à Compile (Компиляция)à Option compare (Метод сравнения строк)

Режимы:

- Binary – с учетом регистра (по умолчанию);

- Text – без учета регистра.


int strcmp(строка 1, строка 2)

Возвращаемое значение равно:

< 0, если строка 1 < строки 2;

=0, если строка 1 == строке 2;

> 0, если строка 1 > строки 2.

Пример.

char str1[20], str[20];

strcpy(str1, " Привет " );

strcpy(str2, " семье! " );

strcat(str1, str2); à " Привет семье! "

if (strcmp(str1, str2)) à str1! = str2


Длина строки

 


Len(строка)
unsigned strlen( char *);

Возвращает число символов в строке без конечного нуля.


Первое вхождение строки s2 в s1


InStr([начальная позиция, ] где ищем, что ищем[, режим сравнения])

Возвращаемое значение: позиция, с которой строка что ищем входит в строку где ищем; если вхождения нет, возвращается 0.

Аргументы:

- начальная позиция – позиция, с которой начинается поиск; если опущена, то поиск с первой позиции;

- режим сравнения: = { Binary | Text }; если опущен, то определяется инструкцией Option Compare; если задан, то начальная позиция обязательна.

Пример.

s1=" 0123456789" : s2=" 345"

k=InStr(5, s1, s2) ' k=0


char* strstr(s1, s2);

Возвращаемое значение: указатель на символ, с которого начинается вхождение s2 в s1;

если вхождения - нет, возвращается NULL.

Пример.

strcpy(s1, " 0123456789" );

­

strcpy(s2, " 345" );

p=strstr(s1, s2);

 


Формирование строки из повторяющихся символов


Строка из пробелов:

Space(число пробелов)

Строка из произвольных повторяющихся символов:

Strdup(число, строка)

Строка строится из первого символа строки.


char* strset(строка, символ)


Другие возможности



Выделение подстрок:

Left(строка, n)n первых символов строки.

Right(строка, n)n последних символов строки.

Mid(строка, начало[, n])n символов строки с позиции начало. Начало с 1.

{Ltrim | Rtrim | Trim}(строка) – удалить пробелы: начальные | конечные | с двух концов строки.

Выравнивание:

Lset(строка, n) – возвращает строку, заполненную символами строки.

Инициализация символьного массива.

char mes[ ]=" Это строка! ";

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

 

Если длина строки меньше n, лишние" правые" символы заменяются пробелами, если больше, берутся первые n символов строки.

Rset(строка, n) – делает то же самое, но пробелами заменяются " левые” символы.

 


Пример. Определить, являются ли 2 строки анаграммой.


Function anagr(str1 As String, _

str2 As String ) As Boolean

Dim len1 As Integer, _

len2 As Integer, _

i As Integer, _

j As Integer, _

fl1 As Boolean = True, _

fl2 As Boolean, _

sled( ) As Boolean

len1=Len(str1): len2=Len(str2)

If len1< > len2 Then Return False

Redim sled(len1-1)

For i=0 To len1-1

sled( i )= False

Next

i=0

Do While i< len1 And fl1

j=0: fl2= True

Do While j< len2 And fl2

If Not sled( j ) And _

Mid(str1, i, 1)= _

Mid(str2, j, 1) Then

sled(j)= True

fl2= False

End If

j+=1

Loop

If fl2 Then fl1= False

i+=1

Loop

Return fl1

End Function
bool anagr( char * str1, char * str2){

short len1,

len2,

i, j;

bool fl1= true, // true – анаграмма

fl2, // f - символ в str2 найден

sled[20]; // true - j-й символ в

//str2 использован

len1=strlen(str1); len2=strlen(str2);

if(len1! = len2) return false;

for (i=0; i< len2; i++)

sled[ i ]= false;

for (i=0; i< len1 & & fl1; i++){

fl2= true;

for (j=0; j< len2 & & fl2; j++){

if (! sled[ j ] & & str1[ i ]==

str2[ j ]){

sled[ j ]= true;

fl2= false;

}

}

if(fl2)fl1= false;

}

return fl1;

}



Замечание. С. Начиная с Visual Studio 2015 запрещена функция gets. Вместо нее следует применять функцию char * gets_s (char *, int size_buf), где size_buf – размер буфера. Все функции из string.h вызывают предупреждения, рекомендуя функции с суффиксом _s и дополнительным 2-м параметром size_buf – размер буфера, например, strcpy_s(res, n, ist). Эти предупреждения можно выключить с помощью # define _CRT_SECURE_NO_WARNINGS.

Динамические объекты

До сих пор для всех объектов, рассматриваемых в пособии, память выделялась по информации программы автоматически. Для объектов класса памяти static и extern во время трансляции в статической области, для объектов класса памяти auto и register динамически (во время выполнения) в области, называемой программным стеком. Однако, в языке C, как и во многих других языках программирования, имеется возможность выделять память под программные объекты прямым указанием программиста. Такие объекты располагаются в отдельной области – куче ( heap ). Их принято называть динамическими.

Для этих целей в языке C++ используются операторы new и delete.

Формат:

new < тип> [< выражение> ]

Выражение используется при выделении памяти под массив. Результат действия оператора – указатель на данный тип.

Пример.

short *shortp = new short ; // Выделение памяти под целое значение

*shortp = 10;

struct str{

char name[40];

short m;

};

str *pstr = new str[*shortp]; // Выделение памяти под 10 элементов типа str

Формат:

delete [ [ ] ]< указатель>

Оператор delete освобождает только память, выделенную оператором new. Квадратные скобки в операторе применяются при освобождении памяти для массива.

Если памяти не хватает, то оператор new возвращает значение NULL. Освободить память в куче можно только оператором delete.

Объекты в куче имен не имеют и работа с ними выполняются исключительно с помощью указателей. Часто говорят, что куча - это неименованная область памяти. Для того, чтобы сделать программу независимой от компьютера и операционной системы, при выделении памяти используют оператор sizeof (< тип> ).

Пример.

sizeof ( short ) à 2 байта

sizeof (DATA) à размер определяется по объявлению типа DATA.

Пример. Динамическое выделение памяти под массив заданного размера n.

char * p= new char [n];

Примеры. Манипуляции с массивом произвольного размера.

float *ptr, buf;

short i, n;

........................................

printf(" Длина массива: " ); scanf(" %hd", & n);

/* Выделить память под массив */

ptr= new float [n]);

/* Ввести массив */

printf(" Исходный массив\n" );

for (i=0; i< n; i++){

scanf(" %f", & buf); *(ptr + i ) = buf; // ptr[ i ] = buf;

}

.................................

delete [ ] ptr;

Функция substr – аналог функции Mid языка Basic.

#include < string.h>

// Выделить из строки s подстроку длиной length с позиции begin

// Если length == 0, выделяется подстрока с begin до конца s

char* substr( char * s, short begin, short length){

char* p; // Подстрока

short i;

if (length == 0) length = strlen(s) – begin + 1; // До конца строки s

/* Обработка ошибки */

if(begin < 1 || length < 1 || begin + length – 1 > strlen(s)) return NULL;

p= new char [length+1];

for (i=0; i < length; i++){

*(p + i) = *(s + begin + i - 1);

}

*(p + i) = 0;

return p;

} // End substr

Замечание 1. В функции память выделяется, но не освобождается, поэтому после того, как необходимость в выделенной памяти отпадет, ее следует освободить оператором delete [ ] < имя_указателя>, которому присвоено возвращаемое значение.

Замечание 2. Для работы в куче можно также использовать функции:

- void *malloc(размер);

- void *calloc(количество, размер элемента); // Под массив

- void free(указатель); // Возвращенный функцией malloc или calloc

Прототипы этих функций находятся в файле stdlib. h.

Применение операторов new и delete является предпочтительным.


Поделиться:



Последнее изменение этой страницы: 2017-04-12; Просмотров: 361; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.166 с.)
Главная | Случайная страница | Обратная связь