русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Пример 4.4


Дата добавления: 2013-12-23; просмотров: 1023; Нарушение авторских прав


Пример 4.3.

Пример 4.2.

# include <stdio.h>

main ()

{

float x = 10.1, y ;

float * pf ;

pf = &x ;

y = *pf ;

printf(“x = %f y= %f”, x, y); // Результат: x=10.1; y=10.1; pf=FFF6

*pf ++;

printf (“x = %f y = %f”, x, y); // Результат: x=10.1; y=10.1 ; pf=FFF2

y =1+ *pf * y;

printf (“x = %f y = %f”, x, y); // Результат: x=10.1; y=1 ; pf=FFF6

return 0;

}

К указателям можно применить операцию присваивания. Указатели одного и того же типа могут использоваться в операции присваивания, как любые другие переменные.

# include <stdio.h>

main ()

{

int x = 0 ;

int *p, *g ;

p = &x ;

g = p ;

printf(“%p”, p); /* печать содержимого p */

printf(“%p”, g ); /* печать содержимого g */

printf(“%d %d”, x., *g);/*печать величины х и величины по адресу g */

}

В этом примере приведена еще одна спецификация формата функции printf() %p – печать адреса памяти в шестнадцатеричной системе счисления.

В языке Си указателю допустимо присвоить любой адрес памяти. Однако, если объявлен указатель на целое int *pi; а по адресу, который присвоен данному указателю, находится переменная типа float, то при компиляции будет выдано сообщение об ошибке в строке

p = &x;

Эту ошибку можно исправить, преобразовав указатель на int к типу указателя на float явным преобразованием типа:

p = (int*)&x;

но при этом теряется информация о том, на какой тип указывал исходный указатель.

Пример неправильной программы:

main ()

{

float x =10.1, y;

int *p;

p = &x /* потом заменим на p=(int*)&x */

y = *p;

printf (“x = %f y = &f \ n”, x, y);

}

В результате работы этой программы не будет получен тот ответ, который ожидался. Переменной y не будет присвоено значение переменной x, т.к. будут обрабатываться не 4 байта, как положено для переменной типа float, а только 2 байта, т.к. базовый тип указателя - int.



Как и над другими типами переменных, над указателями можно производить арифметические операции сложения и вычитания, а также операции (++) и (--). Указатели можно сравнивать. Применимы шесть операций:

<, >, < =, > =, =, = =, ! =

main()

{

int *p;

int x;

p = &x;

printf (“%p%p”, p, ++p);

printf (“%p”, ++p);

}

 

После выполнения этой программы, мы увидим, что при операции ++p значение указателя изменится не на 1, а на 2. И это правильно, т.к. значение

указателя должно указывать не на следующий адрес памяти, а на адрес следующего целого. А целое, как мы помним, занимает 2 байта. Если бы базовой тип указателя был не int, а double, то были бы напечатаны адреса, отличающиеся на 8. Именно столько байт занимает переменная типа double.

К указателям можно прибавлять некоторое целое или вычитать. Пусть указатель p имеет значение 2000 и указывает на целое, тогда в результате выполнения оператора p=p+3 его значение будет 2006. Если указатель p1=2000 был бы указателем на float, то после применения оператора p1= p1+10 значение p1 было бы 2040.

Общая формула для вычисления указателя по формуле p= p+ n будет иметь вид:

<p>=<p>+n*<количество байт памяти базового типа указателя>.

Сравнение p < g указывает, что адрес, находящийся в p, меньше адреса, находящегося в g.

 

 

4.3. Массивы и указатели на языке Си

 

Массивы описывают регулярную структуру данных одного типа.

Одномерные массивы:

int temp [365];

char arr [10];

char *point[10];

Двумерные массивы:

int array[4] [10];

char arr [3] [7];

Число в [ ] указывает количество элементов массива, поэтому:

temp [365] – массив из 365 элементов.

Доступ к каждому элементу осуществляется по его индексу (номеру), т.е. temp[0], temp[1],…,temp[364]- последний элемент. Элементы массива нумеруются начиная с 0.

Можно также использовать многомерные массивы, например: int arr [k] [l] …[n];

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

Рассмотрим, как происходит размещение элементов массива в памяти ЭВМ. Как правило, элементы массива занимают последовательные ячейки памяти. При этом элементы размещаются таким образом, что самый последний индекс возрастает быстрее. Это в случае двумерного массива означает, что он будет записываться построчно: строка за строкой. Поскольку указатели указывают адрес ячейки, то между массивами и указателями существует тесная связь. Вспомним, что имя массива – это указатель на его первый элемент. По существу массив можно рассматривать как индексированный указатель. Доступ к элементам массива осуществляется по номеру индекса. При этом приращение индекса на единицу вызывает перемещение указателя на число байт, соответствующее объекту данного типа: для целых чисел на 2 байта, для действительных - на 4 байта и т.д.

Объявления int mas[] и int *mas идентичны по действию: оба объявляют mas указателем.

Индекс массива действует аналогично стрелки часов, показывающей по очереди на каждый следующий элемент массива.

Пример 4.5:

int mas[10];

int *ptr;

ptr = mas; // присваивает адрес указателю

// следующие операции дадут один и тот же результат:

mas[2] = 20;

*(ptr + 2) = 20;

// следующая операция прибавит 2 к первому элементу:

*ptr + 2;

 

Указатели и многомерные массивы. Рассмотрим двумерный массив и действия с указателями.

int mas[4][2];

int *ptr;

ptr = mas;

ptr сейчас указывает на первый столбец первой строки, т.е.

ptr = = mas = = &mas [0] [0];

Увеличим указатель:

ptr+1 = = &mas [0] [1];

ptr+2 = = &mas [1] [0];

ptr+3 = = &mas [1] [1] и т.д.

Двумерный массив можно представить как массив массивов. В нашем случае мы имеем четырех элементный массив, состоящий из двух элементов. Примечательно, что этот четырех элементный массив можно представить в виде одномерного mas[0],…,mas[3]. При этом имя массива по-прежнему является указателем на его первый элемент, т.е. mas[0]= =&mas[0] [0] . На что же будут указывать mas[i]? В этом случае mas [i] указывает на i-тую строку, т.е. на первый элемент i - й строки. Таким образом

mas [0] == &mas [0] [0];

mas [1] == &mas [1] [0];

mas[2] == &mas [2] [0];

mas[3] == &mas [3] [0];

Массивы и указатели – различия.

Имя массива – является указателем – константой. Описания:

char string_1[20]= «Язык Си» и

char *string_2 = «Язык Си»;

размещают в памяти соответствующую строку символов. Различие состоит в том, что указатель string_1 является константой, а указатель string_2 – переменной. Это различие проявляется в случае использования операции единичного приращения ++. Эту операцию можно применять только к переменным. Поэтому string_2++ - допустимая конструкция, а string_1++ - запрещенная. Однако и в том и в другом случае можно использовать операции сложения с указателем, т.е.

string_1 + i ;

string_2 + i ; - допустимые конструкции.

При задании массива символов можно указывать размер явно, например:

char mas_1 [10] = “Яблоко”;

Или определить массив по умолчанию

Char mas_2 [ ] = “Груша”.

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

Массивы и указатели символьных строк

Часто бывает необходимо иметь массив символьных строк. При этом возможно задать два типа описаний:

1) char string_1[10][20]; //10 строк по 20 символов

2) char* string_2[10]; // массив из 10 указателей на строки символов. Какие здесь различия? Различие заключается в том, что в первом случае задается “прямоугольный” массив, в котором каждая строка имеет фиксированную длину, а во втором определяется “рваный” массив, где длина каждой строки занимает столько байт , сколько необходимо.

Например:

char string_1[3] [7] ={“Яблоко”, “Слива” , “Груша”};

char *string_[3]={“яблоко”, “слива”, “груша”};

Заполнение массивов будет следуюим:

string_1: string_2:

Яблоко\0 яблоко\0

Слива\0\0 слива\0

Груша\0\0 груша\0

 



<== предыдущая лекция | следующая лекция ==>
Объявление и инициализация массивов | Типовая структура программы на языке СИ


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.004 сек.