Программирование >>  Унарные и бинарные операторы 

1 ... 8 9 10 [ 11 ] 12 13 14 ... 37


Объявление функции fC), принимающей массив а, состоящий из п элементов типа char, выглядит так: fCint п. char а[]):

Запись char[] показывает, что функция принимает массив, а отсутствие размера в квадратных скобках говорит о том, что это не важно, все равно функция знает только указатель на нулевой элемент, а размер передается в другой переменной. Чтобы подчеркнуть, что функции передается именно указатель, а не сам массив, ее прототип можно записать так:

f(int п. char *а):

Последняя запись лучше отражает суть происходящего, зато предыдущая более понятна тем, кто знаком с языком Бейсик или Фортран. В листинге 5.6 показано, как функция meanC) вычисляет среднее значение элементов массива.

Листинг 5.6

#include <iostream>

using namespace std;

double niean(int n. double *a){

double sum=0:

fcr(int i=0: i <n: i++)

sum += a[i]: return sura/n: }

main{){

double t[]={36.6.37.6.38.5.41.5.36.3.36.5}: cout mean{6.t) endl: return 0: }

Заметим, что размер массива t[] автоматически определяется компилятором по числу начальных значений его элементов в фигурных скобках. Функгии meanO передается размер массива (в нашем случае 6) и указатель на его нулевой элемент, то есть просто имя t. Доступ ко всем элементам массива, обеспеченный указателем, функция mean() использует честно - для нахождения

среднего. Но ничто не мешает ей попробовать записать число туда, где массива уже нет, например в седьмой его элемент, и тем самым разрушить программу. Нужно понимать, что компилятор не контролирует выход за границы массива, считая, что этим должен заниматься программист. Здесь таится большая опасность, поэтому обращаться с массивами и указателями следует очень осторожно.

Массив указателей

Наши знания массивов и указателей возросли настолько, что становится возможным изучить давно скрываемые параметры функции mainC). Заглянув в пространство между круглыми скобками, увидим два параметра:

int main(int argc. char *argv[]){}

Первый из них (целочисленная переменная argc) нам вполне понятен. Зато второй выглядит странно. Что такое char *argv[] - массив или указатель? И то и другое. Запись char *argv[ ] обозначает в С++ массив указателей, то есть массив, в котором хранятся указатели на тип char. Размер этого массива не указан, но, вспомнив функцию mean С) из предыдущего раздела, легко догадаться, что он задается параметром argc.

Теперь нужно понять, что и при каких обстоятельствах передается функции mainO. Оказывается, в массиве argv[ ] помещаются указатели на отдельные элементы командной строки программы, запускаемой в окне DOS. Одна из таких программ хорошо нам известна - это компилятор gcc. Представим себе, что необходимо скомпилировать программу test.cpp. Для этого нужно перейти в папку, где хранится соответствующий файл, и запустить компилятор, указав в его командной строке следующую команду:

gcc test.cpp -о test.exe



В ЭТОМ случае функция mainC) в программе gcc получит параметры, показанные на рис. 5.2. Первый параметр, имя программы и полный путь к ней (в нашем случае это f:\gcc\bin\gcc.exe), передается всегда, поэтому агдс не может быть меньше единицы. Остальные параметры добываются из командной строки, причем считается, что один пара.метр от другого отделяет пробел (или несколько пробелов).

gcc test.cpp -о lest.exe argc=4

argv[01

argvfll

argvI21

argv[31

F:\GCC\B1N\GCC.EXE\0

test.cppVO

-o\0

test.exeW

Рис. 5.2. Параметры, полученные функцией mainO

Итак, параметров, на которые указывают элементы argv[], в пашем случае четыре: путь к програ.\гме и три параметра, передаваемых в командной строке: test.cpp, -о, test.exe. Очевидно, argv[l] - это указатель на нулевой элемеш массива, в котором хранятся символы test.cppVO. Всего их девять - семь букв, точка и завершающий символ \0, добавляемый компилятором, чтобы обозначить конец последовательности (подробнее о нем см. раздел Массивы в главе 4).

Теперь мы знаем, как устроены парамст1;)ы функции tiiainC), но чтобы научиться ими пользоваться, нужно, как обычно, па1Н1сать собственную программу, обрабаты-ваюп1ую ключи командной строки.

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

Листинг 5.7

#inc1ude <iostreanP

using namespace std:

int maindnt argc, char *argv[]){

if (argc < 2){

cout arc <-ae1> файл endl:

return 1;

if(*argv[l] != -){

cout неверный формат endl: return 1:

char ch=*Cargv[l]+l): switch(ch){ casea :

cout добавить endl:

break: casee:

cout распаковать endl:

break: casel:

cout листинг endl:

break: default:

cout ошибка endl:

break:

return 0: }

Инструкция if (argc < 2){} проверяет, есть ли параметры в командной ст]юке. Если аргумент argc paBeFi едипице, параметров нет, и программа завершается, показав на экране, как ею пользоваться.



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

if(*argv[l] !=- ){

Как мы знаем, ergv[l] - это указатель на нулевой символ первого параметра. Оператор * превращает указатель на символ в сам символ, таким образом условие {*argv[l] .= - ) проверяет, равен ли нулевой символ первого параметра дефису. Если да - разбор продолжается, если нет - программа заканчивает работу, предварительно сообщив об ошибке.

Если нулевой символ параметра равен дефису, то нужно получить первый символ, что и делает инструкция char ch=*Cargv[l]+l). Смысл ее прост: argv[l] -это указатель на нулевой символ. Очевидно, argv[l]+l указывает на пе/?вь<й символ. Чтобы из указателя получить сам элемент, необходимо применить к нему оператор *. Получается, что ch=*(argv[l]+l) иесть первый символ параметра.

Теперь нужно проверить, тот ли это символ, для чего используется условная инструкция switch О, с которой мы еще незнако1ш>1. Смысл ее прост. В круглых скобках после слова switch показывается выражение, а его возможные значения перечисляются строками case. Если выражение приняло указанное значение, то выполняются инструкции, стоящие после case, а дальше инструкция break передает управление программой за пределы переключателя (так обычно называется инструкция switch). Без инструкции break программа перейдет к проверке следующего значения, что нежелательно и может привести к путанице. Наконец, строка defaul t - это свое-

образный сборщик мусора , сюда попадают все значения, не упомянутые строками case.

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

Указатель на указатель

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

Действительно, попробуем понять, что такое argv. Очеввдно, это имя массива указателей. И, согласно нашему пониманию массива, argv указывает на нулевой его элемент. Но что такое этот элемент? Очевидно, указатель. Значит, argv - это указатель па указатель. Такие объекты объявляются в С++ как char **argv, поэтому прототип функции mainO можно записать и так:

int maindnt argc. char **argv):

Зная, что argv - указатель на указатель, можно немного но-дрзо-ому органи.зовать разбор параметров командной строки. Очевидно, argv указывает на argv[0]. Прибавив единицу к argv, получим указатель на argv[l]. Применив к такому указателю оператор *, получим само значение argvCl]. Но argv[l] - это указатель на char. Чтобы получить самозначение (нулевой символ первого параметра командной строки), нужна еще одна звездочка **(argv+l). Иными словами, проверка i f (*argv[l] !=-) из листинга 5.3 может быть зшшсана как if C**{argv+1) !=-).

Объявление показывает, что оператор *, примененный к объекту argv дважды, дает значение char.



1 ... 8 9 10 [ 11 ] 12 13 14 ... 37

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика