Турбо С: руководство пользователя. Часть 1

Турбо С: руководство пользователя. Часть 1 - Стр. 67

Печать PDF
Индекс материала
Турбо С: руководство пользователя. Часть 1
Стр. 2
Стр. 3
Стр. 4
Стр. 5
Стр. 6
Стр. 7
Стр. 8
Стр. 9
Стр. 10
Стр. 11
Стр. 12
Стр. 13
Стр. 14
Стр. 15
Стр. 16
Стр. 17
Стр. 18
Стр. 19
Стр. 20
Стр. 21
Стр. 22
Стр. 23
Стр. 24
Стр. 25
Стр. 26
Стр. 27
Стр. 28
Стр. 29
Стр. 30
Стр. 31
Стр. 32
Стр. 33
Стр. 34
Стр. 35
Стр. 36
Стр. 37
Стр. 38
Стр. 39
Стр. 40
Стр. 41
Стр. 42
Стр. 43
Стр. 44
Стр. 45
Стр. 46
Стр. 47
Стр. 48
Стр. 49
Стр. 50
Стр. 51
Стр. 52
Стр. 53
Стр. 54
Стр. 55
Стр. 56
Стр. 57
Стр. 58
Стр. 59
Стр. 60
Стр. 61
Стр. 62
Стр. 63
Стр. 64
Стр. 65
Стр. 66
Стр. 67
Стр. 68
Стр. 69
Все страницы
                                                                                
          Использование указателей  может быть наиболее трудно для по-          
     нимания начинающему программисту на Си.  Когда надо  использовать          
     указатели, а    когда нет?  Когда использовать косвенный оператор          
     (*)? Когда  использовать адресный оператор (&)?  И  как  избежать          
     ошибок операционной системы во время выполнения программы?                 
                                                                                
          На все  эти и многие  другие вопросы ответ  будет дан в этом          
     разделе.                                                                   
                                                                                
                                                                                
                                                                                
          Использование неинициализированных указателей                         
     -----------------------------------------------------------------          
                                                                                
          Одна серьезная опасность таится в присвоении значения по ад-          
     ресу, содержащемуся  в указателе,  без первоначального присвоения          
     адреса этому указателю.                                                    
                                                                                
          Например:                                                             
                                                                                
                   main()                                                       
                                                                                
                   {                                                            
                       int *iptr;                                               
                                                                                
                       *iptr = 421;                                             
                       printf("*iptr = %d\n",*iptr);                            
                   }                                                            
                                                                                
          Эта ловушка опасна тем,  что программа, содержащая ее, может          
     быть "верна"   и  компилятор может не выдать никаких сообщений во          
     время компиляции такой программы. В примере, указанном выше, ука-          
     затель iptr имеет некоторый произвольный адрес, по которому запо-          
     минается значение 421. Эта программа настолько мала, что шанс что          
     -нибудь  затереть  в  памяти с ее помощью ничтожно мал,  однако в          
     больших  программах  возрастает  вероятность  разрушения   других          
     данных,  поскольку  вполне  возможно,  что  по  адресу  iptr  уже          
     хранится другая информация.  Если  вы  используете  модель  самой          
     маленькой  памяти  (tiny),  в которой сегменты программы и данных          
     занимают одну и ту же область  памяти,  то  вы  подвергаете  себя          
     риску испортить свой же загрузочный модуль. Поэтому старайтесь не          
     рубить сук на котором вы сами  же  сидите  и  внимательно  пишите          
     программы, использующие указатели.                                         
                                                                                

                         - 553,554 -
                                                                                
     Строки                                                                     
     -----------------------------------------------------------------          
                                                                                
          Как мы уже говорили,  строки можно объявить как указатели на          
     тип данных char или как массивы данных типа char. Речь шла о том,          
     что между ними существует лишь одно важное различие:  если вы ис-          
     пользуете указатель на данные типа char, память для строки не ре-          
     зервируется; если вы используете массив данных,  то память резер-          
     вируется автоматически и переменная  -  имя  массива  -  содержит          
     адрес начала зарезервированной области памяти.                             
                                                                                
          Недостаточное понимание  этой  разницы может привести к двум          
     типам ошибок. Рассмотрим следующую программу:                              
                                                                                
                   main()                                                       
                   {                                                            
                       char *name;                                              
                       char msg[10];                                            
                                                                                
                       printf("Назовите свое имя.");                            
                       scanf("%s",name);                                        
                       msg = "Здраствуйте, ";                                   
                                                                                
                       printf("%s %s:",msg,name);                               
                   }                                                            
                                                                                
          На первый  взгляд все законно,  немного неуклюже,  но вполне          
     допустимо. Однако здесь допущены две ошибки.                               
                                                                                
          Первая ошибка содержится в выражении:                                 
                                                                                
                   scanf("%s",name).                                            
                                                                                
          Выражение само по себе законно и корректно.  Поскольку  name          
     является указателем  на char,  вам не нужно ставить перед ним ад-          
     ресный оператор (&).  Однако память для name не  зарезервирована;          
     строка, которую вы введете, будет записана по какому-то случайно-          
     му адресу,  который окажется в name. Компилятор обнаружит это, но          
     поскольку эта   ситуация  не приведет к сбою выполнения программы          
     (т.к. строка все же будет сохранена),  то компилятор выдаст  лишь          
     предупреждающее сообщение, но не ошибку.                                   
                                                                                
                 "Possible use of 'name' before definition"                     
           ("Возможно использование 'name' до ее определения")                  
                                                                                

                         - 555,556 -
                                                                                
          Вторая ошибка содержится в операторе msg =  "Здравствуйте,".          
                                           
                   main()                                                       
                   {                                                            
                        char *name;                                             
                        char msg[10];                                           
                                                                                
                        name = (char *) malloc (10);                            
                        printf("Назовите свое имя");                            
                        scanf("%s",name);                                       
                        strcpy(msg,"Здраствуйте,");                             
                        printf("%s%s",msg,name);                                
                   }                                                            
                                                                                
          Вызов функции  malloc  выделяет  отдельно 10 байтов памяти и          

                         - 557,558 -
                                                                                
                                                                                
     присваивает адрес этого участка памяти name,  решив  нашу  первую          
     проблему. Функция   strcpy производит посимвольное копирование из          
     строковой константы string "Здравствуйте," в массив msg.                   
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
                                                                                
               Разница между присваиванием (=) и равенством (==)                
     ----------------------------------------------------------------           
                                                                                
          В языках Паскаль и Бейсик проверка на равенство производится          
     выражением                                                                 
                                                                                
                               if (a = b).                                      
                                                                                
          Для Си  эта  конструкция допустима,  но имеет несколько иное          
     значение. Посмотрите на этот фрагмент программы:                           
                                                                                
                          if (a = b) puts("Равно");                             
                          else       puts("Не равно");                          
                                                                                
          Если это  программа  на  Паскале  или Бейсике,  то вы можете          
     предполагать, что будет напечатано "Равно", если a и b имеют оди-          
     наковое значение и "Не равно" в противном случае.                          
                                                                                
          Иначе происходит с программой на Си, где выражение a = b оз-          
     начает "Присвоить значение b переменной a",  и все выражение при-          
     нимает значение b.  Поэтому во фрагменте, приведенном выше, прис-          
     воится значение b переменной a,  а  затем  напечатается  "Равно",          

                         - 559,560 -
                                                                                
                                                                                
     если b имеет нулевое значение, в противном случае - "Не равно".            
                                                                                
          Правильное решение следующее:                                         
                                                                                
                          if (a == b) puts("Равно");                            
                          else        puts("Не равно");