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


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

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



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

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

Раздел деклараций (Declarations)

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

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

Раздел процедур

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

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

Декларации

определения символических констант (#define)

включаемые файлы (#include)

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

Функции

void main(void){

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

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

}

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

 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5. Что понимают под проектом приложения?

 

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

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

Указатели

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

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

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

Пример.

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(double zap[ ], short n){

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 */


void sort(double *zap, short n){

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 */


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

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

double x[10][10];

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

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

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

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


Литералы

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

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

Пример.

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

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

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

Пример.

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

Переменные


Basic

Тип данных string.

2 вида: строки переменной и фиксированной длины.

Объявление:

<имя> as string [*<длина>]

 

C

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

Вместо строковых переменных используются массивы типа char. Следовательно, они аналогичны строкам фиксированной длины языка Basic.

Объявление:

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


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


Basic

C



Ввод - вывод



Ввод строки в окноInputBox (поясняющий текст[, заголовок окна] [,значение по умолчанию][,xнач] [, yнач]).

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

Аргументы:

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

- значение по умолчанию – значение, появляющееся в поле ввода; если пользователь согласен с

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

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


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

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

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

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

Введенное значение заносится

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

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

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

char str1[20], str2[20];

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

gets(str1);

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



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


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

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

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

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

Аргументы:

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

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

 
 

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


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

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

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

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

 



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

 


Оператор &


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

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


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


Оператор =

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

 


 


Сравнение


Оператор =

Пример.

dim str1 as string, str2 as string

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

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

if str1 = str2 then ' Результатà false

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

option compare <режим>

Режимы:

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

- text – без учета регистра;

- database – для MS Access.
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 | database }; если опущен, то определя-ется инструкцией option compare; если задан, то начальная позиция обязательна.

Пример.

s1="0123456789": s2="345"

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


char* strstr (где ищем, что ищем);

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

Пример.

strcpy(s1, "0123456789");

­

strcpy(s2, "345");

p=strstr(s1, s2);

 


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


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

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

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

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

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


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



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



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

- left (строка, n)n первых символов строки;

- right (строка, n)n последних символов строки;

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

- trim (строка) – удалить пробелы с двух концов строки.

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

Инструкция lset строка1 = строка2

Присваивает строке1 значение строки2 и, если длина строки1 бол ьше длины строки2, лишние "правые" символы заменяются пробелами.

Инструкция rset строка1 = строка2

Делает то же самое, но "прижимает" строку2 к "правой" границы строки1.


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

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

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


Пример. Определить, являются ли 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, _

fl2 as boolean, _

sled() as boolean

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

if len1<>len2 then

anagr= false

Exit function

End if

redim sled(1 to len1)

for i=1 to len1

sled(i)= false

Next

i=1: fl1= true

do while i<=len1 and fl1

j=1: 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=j+1

loop

if fl2 then fl1= false

i=i+1

loop

anagr=fl1

end function
short anagr(char * str1, char * str2){

short len1,

len2,

i, j,

fl1=1,// 1 - анаграмма, 0 - нет

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

// 0 - нет

sled[20]; /* 1 - j-й символ в str2

использован, 0 – нет */

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

if(len1!= len2) return 0;

for (i=0; i<len2; i++)sled[ i ]=0;

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

fl2=1;

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

if (!sled[ j ] && str1[ i ]==str2[ j ]){

sled[ j ]=1;

fl2=0;

}

}

if(fl2)fl1=0;

}

return fl1;

}


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

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

Для этих целей в библиотеки языка C включены функции malloc, calloc и free. Их прототипы хранятся в файле alloc.h.

Выделение памяти.

void* malloc (unsigned size); // Размер в байтах

void* calloc (unsigned kol, // Число элементов

unsigned size); // Размер в байтах

Освобождение памяти: void free (void *ptr);

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

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

Пример.

sizeof ( short ) à 2 байта

sizeof (DATA) à размер определяется по инструкции typedef.

Функции malloc и calloc возвращают указатель на void, который не может использоваться для ссылки на объект, поэтому при размещении объектов в куче программист обязан задать тип размещаемого объекта с помощью оператора приведения типа.

Пример. Динамическое выделение памяти под массив заданного размера n. p=(char*) malloc (n* sizeof (char)); p=(char *)calloc(n, sizeof (char));

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

float *ptr, buf;

short i, n;

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

printf("Длина массива:");

scanf("%d", &n);

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

ptr=( float *)calloc(n, sizeof (float));

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

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

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

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

}

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

free(ptr);

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

#include <string.h>

#include <alloc.h>

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

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

char* substr(const 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=(char*)calloc(length + 1, sizeof (char));

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

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

}

*(p + i) = '\0';

return p;

} /* End substr */

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



Поделиться:


Последнее изменение этой страницы: 2017-02-08; просмотров: 319; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.191.171.235 (0.182 с.)