bmstu_iu6_Cpp1 (823967), страница 14
Текст из файла (страница 14)
Такесли к функциям предыдущего примера добавить функциюbcd()Оглавление87{int a;…// автоматическая переменная, «перекрывающая» внешнюю}то внешняя переменная a становится в подпрограмме bcd() е недоступной: все обращенияиз этой подпрограммы будут выполняться к внутренней автоматической переменной a.По умолчанию все переменные, описанные внутри функции, – автоматические, т.е.описатель auto для них можно не применять, например:int main(){int a;…// автоматическая переменная (по умолчанию)}abc(){auto int a;…}// автоматическая переменнаяАвтоматические переменные функции main обладают особыми свойствами: времяих жизни совпадает со временем работы всей программы и они доступны по имени извсех ее функций, что по свойствам делает эти переменные похожими на внешние.3. Статические переменные (описатель static). Размещение – глобальная памятьподпрограммы (сегмент данных), область действия – внутри функции, в которой она определена, время жизни – все время работы программы.
В отличие от автоматической статическая переменная не исчезает, когда функция завершает работу, по сравнению с внешней– недоступна из всех функций программы, кроме той, в которой была определена.abc(){int a=1;// автоматическая переменнаяstatic int b=1;// статическая переменная…a++;// каждый раз инициализируется зановоb++;// инициализируется один раз при первом обращении и…// увеличивается с каждым вызовом функции}4.
Внешние статические переменные (описатель extern static). Размещение –глобальная память модуля (файла), область действия – внутри всех функций модуля(файла) программы, где она определена, время жизни – с момента вызова программы и довозврата управления операционной системе.Оглавление88Например:файл Mod1.cpp:int a;// внешняя переменная (по умолчанию)extern static int b; // внешняя статическая переменнаяфайл Mod2.cpp:int abc(){ h=a; …}Переменная a доступна в обоих файлах, переменная b – только в первом.5. Регистровые переменные (описатель register). Регистровые переменные аналогичны автоматическим, но по возможности должен их размещать в регистровой памятипроцессора, например:register int a;Такое размещение ускоряет операции над этими переменными.
Однако свободныхрегистров обычно очень мало (1-2), и возможность их использования сильно зависит отостального текста программы. Если регистры заняты, то переменная размещается аналогично переменной auto.По возможности следует использовать автоматические переменные. Это снижает зависимость функций и существенно уменьшает количество ошибок в программах.4.1.2 Параметры сложных структурных типовПередача массивов в подпрограммы. В силу специфики организации массивов вСи и С++ массивы передаются в подпрограммы как указатели на первый элемент. Размерность массива по первому индексу при этом не контролируется.
Это вызвано тем, что С++ проверяет соответствие фактических и формальных параметров функции только по порядку и по типу, причем понятие типа при этом не включает конкретной размерности массива.Следовательно, при передаче одномерного массива в качестве параметра достаточноуказать, что этот параметр – массив или вообще описать указатель на элемент, а при работе с многомерными массивами можно не указывать размерность по первому индексу.Тогда, допустимы следующие варианты описания параметров-массивов:а) int x[5] ⇔ int x[] ⇔ int *x // размерность проверяться не будетб) int y[4][8] ⇔ int y[][8] // будет проверяться размерность массива// только по второму размеруОглавление89При этом если в функцию передается массив, значения которого не должны менятьсявнутри функции, его следует описать как const, например:int k23(const int *a);Пример 4.2. Написать функцию формирования в отдельном массиве сумм строк матрицы.#include <locale.h>#include <stdio.h>#include <conio.h>const int stringNum=5;void summa(const float x[][3], float y[],int n);int main(int argc, char* argv[]){setlocale(0,"russian");float a[stringNum][3]={{3.1,2.4,1.6},{6.1,9.3,1.3},{2.4,1.9,1.4},{-9.0,4.5,1.9},{7.2,8.0,1.8}},float y[stringNum];summa(a,y, stringNum);for (int i=0;i< stringNum;i++) printf("%6.1f",y[i]);puts("\nНажмите любую клавишу для завершения...");_getch();return 0;}void summa(const float x[][3], float y[],int n){int i,j;for(i=0;i<n;i++)for(y[i]=0,j=0;j<3;j++) y[i]=x[i][j];}Пример 4.3.
Написать подпрограмму удаления из матрицы l-ой строки и k-го столбца. Исходная матрица должна формироваться тестирующей программой с помощью датчика случайных чисел.#include <locale.h>Оглавление90#include <stdio.h>#include <conio.h>#include <math.h>#include <time.h>#include<stdlib.h>void delsts(int a[][10],int & n,int & m,int l,int k){int i,j;// удаление строкиfor(i=l;i<n-1;i++)for(j=0;j<m;j++) a[i][j]=a [i+1][j];// удаление столбцаfor(j=k;j<m-1;j++)for(i=0;i<n;i++) a[i][j]=a[i][j+1];n--;m--;}int main(int argc, char* argv[]){setlocale(0,"russian");int matr[10][10],n,m,l,k,i,j;puts("Введите n,m<=10");scanf("%d %d",&n,&m);puts("Исходная матрица:");srand( (unsigned)time( NULL )); // установка датчика случайных чиселfor(i=0;i<n;i++){for(j=0;j<m;j++){matr[i][j]=rand()/1000;// вызов датчика случайных чиселprintf("%4d",matr[i][j]);}printf("\n");}printf("Введите l< %5dk<%5dдля удаления\n",n,m);scanf("%d %d",&l,&k);delsts(matr,n,m,l,k);// вызов функции удаления l строки и k столбцаputs("Полученная матрица:");Оглавление91for(i=0;i<n;i++){for(j=0;j<m;j++) printf("%4d",matr[i][j]);printf("\n");}puts("Нажмите любую клавишу для завершения...");_getch();return 0;}Параметры – строки.
При разработке функций, работающих со строками, обычноиспользуют прием, который применяется в стандартных функциях обработки строк: обеспечение возможности вызова функций как процедур и как функций. Это достигается тем,что адрес результирующей строки дублируется и возвращается еще и как результат функции.Рассмотрим несколько примеров.Пример 4.4. Написать подпрограмму удаления «лишних» пробелов. Лишними приэтом считать многократные пробелы между словами и пробелы перед началом и после завершения предложения. Функция получает в качестве входного параметра константнуюстроку, преобразует ее и возвращает в качестве результата преобразованную строку и указатель на строку-результат.Описание функции:#include <locale.h>#include <stdio.h>#include <conio.h>#include <string.h>char * strdel(const char * tstring,char * trez){char *ptr;strcpy(trez,tstring);while( (ptr=strstr(trez,""))!=NULL ) strcpy(ptr,ptr+1);return trez;}Оглавление92int main(int argc, char* argv[]){setlocale(0,"russian");char st[40],st2[40],*ptr2;puts("Введите строку: слова и пробелы:");gets(st);puts("Исходная строка:");puts(st);strdel(st,st2);// вызов подпрограммы как процедрыputs("Полученная строка 1");puts(st2);printf("Полученная строка 2:\n");ptr2=new char [40];puts(strdel(st,ptr2)); // вызов подпрограммы как функцииputs("Нажмите любую клавишу для завершения...");_getch();return 0;}Пример 4.5.
Написать подпрограмму нахождения максимального слова строки. Адрес этого слова возвращается также как результат функции.#include <locale.h>#include <stdio.h>#include <conio.h>#include <string.h>char * maxworld(const char * s,char* slmax);int main(int argc, char* argv[]){setlocale(0,"russian");char st[80],maxsl[10];puts("Введите строку: слова и пробелы:");gets(st);printf("В строке слово ");// вызов подпрограммы как функцииprintf("""%s"" - с мах длиной.\n",maxworld(st,maxsl));maxworld(st,maxsl); // вызов подпрограммы как процедурыОглавление93printf("В строке слово ");printf("""%s"" - с мах длиной.\n", maxsl);puts("Нажмите любую клавишу для завершения...");_getch();return 0;}char * maxworld(const char * s,char* slmax){char slovo[10];unsigned int i,j,dls,maxl;dls=0;slmax[0]='\0';maxl=0;j=0;for(i=0;i<=strlen(s);i++){if ((s[i]==' ')||(s[i]=='\0')){slovo[j]='\0';if (dls>maxl){maxl=dls;strcpy(slmax,slovo);}slovo[0]='\0';j=0;dls=0;}else{dls++;slovo[j++]=s[i];}}return slmax;}3.
Параметры-структуры. В отличие от массивов и строк переменная типа «структура» не является указателем, поэтому если структура передается в качестве параметра, тодля нее действуют те же правила, как и для скалярных значений. Так для передачи в подпрограмму параметров типа «структура», значения которых необходимо вернуть в вызываОглавление94ющую программу, необходимо использовать ссылки или указатели.
В случае, когда изменение полей структуры не требуется, рекомендуется для исключения лишнего копирования всей структуры передавать её по ссылке со спецификатором const.Пример 4.6. Дан массив целых чисел на 10 элементов. Данные о массиве объединены в структуру massive, содержащую 3 поля: массив, его текущий размер и сумму элементов. Написать подпрограмму, получающую структуру massive в качестве параметра,вычисляющую сумму элементов массива и возвращающую эту структуру, как результат свычисленной суммой элементов.Реализовать передачу изменяемой структуры в подпрограмму можно с использованием указателя или ссылки.
Результат будет одинаков, а вот синтаксис описания и вызоваподпрограммы будут отличаться.Вариант 1. Использование указателя на структуру в качестве параметра функции:#include <locale.h>#include <stdio.h>#include <conio.h>struct mas{int n, a[10], sum;};int summa(struct mas *x);int main(int argc, char* argv[]){setlocale(0,"russian");int i;struct mas massive;puts("Введите количество элементов:");scanf("%d",&massive.n);puts("Введите элементы:");for (i=0;i<massive.n;i++) scanf("%d",&massive.a[i]);printf("Сумма элементов=%4d.\n",summa(&massive));puts("Нажмите любую клавишу для завершения...");_getch();return 0;}Оглавление95int summa(struct mas *x) // передается указатель на структуру{int i,s=0;s+=x->a[i]; // суммирование элементовfor (i=0;i<x->n;i++)// запись суммы элементов в поле структурыx->sum=s;return s;}Вариант 2.