Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Указатели в С.doc
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
214 Кб
Скачать
☆

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

Указатель хранит адрес области памяти. Можно создать указатель на указатель, тогда он будет хранить адрес указателя и сможет обращаться к его содержимому. Указатель на указатель определяется как

?

<тип> **<имя>;

Очевидно, ничто не мешает создать и указатель на указатель на указатель, и указатель на указатель на указатель на указатель и так далее. Это нам понадобится при работе с двумерными и многомерными массивами. А вот простой пример, как можно работать с указателем на указатель.

?

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

#include <conio.h>

#include <stdio.h>

   

#define SIZE 10

 

void main() {

    int A;

    int B;

    int *p;

    int **pp;

 

    A = 10;

    B = 111;

    p = &A;

    pp = &p;

 

    printf("A = %d\n", A);

    *p = 20;

    printf("A = %d\n", A);

    *(*pp) = 30;    //здесь скобки можно не писать

    printf("A = %d\n", A);

 

    *pp = &B;

    printf("B = %d\n", *p);

    **pp = 333;

    printf("B = %d", B);

 

    getch();

}

Рекомендация

В общем случае лучше избегать использования указателей. При работе с массивами лучше использовать индексы.

Указатели стоит использовать только в строго определённых ситуациях:

  • В коде нижнего уровня, работающем непосредственно с оперативной памятью или внешними устройствами.

  • Для возврата из функций значений нескольких объектов или для возврата больших объектов как результатов функций.

  • При работе с контейнерами полиморфных объектов.

Примеры

1. Пройдём по массиву и найдём все чётные элементы.

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

#include <conio.h>

#include <stdio.h>

   

void main()

{

    int A[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    int even[10];

    int evenCounter = 0;

    int *iter, *end;

 

    //iter хранит адрес первого элемента массива

    //end хранит адрес следующего за последним "элемента" массива

end = &A[10];

    for (iter = A; iter < end; iter++)

{

        if (*iter % 2 == 0)

            even[evenCounter++] = *iter;

      }

 

    //Выводим задом наперёд чётные числа

    for (--evenCounter; evenCounter >= 0; evenCounter--)

{

        printf("%d ", even[evenCounter]);

     }

 

    getch();

}

2. При сортировке элементов часто приходится их перемещать. Если объект занимает много места, то операция обмена местами двух элементов будет дорогостоящей. Вместо этого можно создать массив указателей на исходные элементы и отсортировать его. Так как размер указателей меньше, чем размер элементов целевого массива, то и сортировка будет происходить быстрее. Кроме того, массив не будет изменён, часто это важно.

?

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

#include <conio.h>

#include <stdio.h>

   

#define SIZE 10

 

void main() {

    double unsorted[SIZE] = {1.0, 3.0, 2.0, 4.0, 5.0, 6.0, 8.0, 7.0, 9.0, 0.0};

    double *p[SIZE];

    double *tmp;

    char flag = 1;

    unsigned i;

 

    printf("unsorted array\n");

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

        printf("%.2f ", unsorted[i]);

    }

    printf("\n");

 

    //Сохраняем в массив p адреса элементов

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

        p[i] = &unsorted[i];

    }

 

    do {

        flag = 0;

        for (i = 1; i<SIZE; i++) {

            //Сравниваем СОДЕРЖИМОЕ

            if (*p[i] < *p[i-1]) {

                //обмениваем местами АДРЕСА

                tmp = p[i];

                p[i] = p[i-1];

                p[i-1] = tmp;

                flag = 1;

            }

        }

    } while(flag);

 

    printf("sorted array of pointers\n");

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

        printf("%.2f ", *p[i]);

    }

    printf("\n");

 

    printf("make sure that unsorted array wasn't modified\n");

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

        printf("%.2f ", unsorted[i]);

    }

 

    getch();

}

3. Более интересный пример. Так как размер типа char всегда равен 1 байт, то с его помощью можно реализовать операцию swap – обмена местами содержимого двух переменных.

?

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

#include <conio.h>

#include <conio.h>

#include <stdio.h>

 

void main()

{

    int length;

    char *p1, *p2;

    char tmp;

    float a = 5.0f;

    float b = 3.0f;

 

    printf("a = %.3f\n", a);

    printf("b = %.3f\n", b);

 

    p1 = (char*) &a;

    p2 = (char*) &b;

    //Узнаём сколько байт перемещать

    length = sizeof(float);

    while (length--)

{

        //Обмениваем местами содержимое переменных побайтно

        tmp = *p1;

        *p1 = *p2;

        *p2 = tmp;

        //не забываем перемещаться вперёд

        p1++;

        p2++;

     }

 

    printf("a = %.3f\n", a);

    printf("b = %.3f\n", b);

 

    getch();

}

В этом примере можно поменять тип переменных a и b на double или любой другой (с соответствующим изменением вывода и вызова sizeof), всё равно обмениваются местами байты двух переменных.

4. Найти длину строки, введённой пользователем, используя указатель

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#include <conio.h>

#include <stdio.h>

 

void main()

{

    char buffer[128];

    char *p;

    unsigned length = 0;

 

    scanf("%127s", buffer);

    p = buffer;

    while (*p != '\0')

{

        p++;

        length++;

    }

 

    printf("length = %d", length);

    getch();

}

Обратите внимание на участок кода

?

11

12

13

14

while (*p != '\0')

{

    p++;

    length++;

}

его можно переписать

?

11

12

13

14

while (*p != 0)

{

    p++;

    length++;

}

или

?

11

12

13

14

while (*p)

{

    p++;

    length++;

}

или, убрав инкремент в условие

?

11

12

13

while (*p++)

{

    length++;

}

Персональный сайт Тенишева Дамира Шамильевича. (с) Damir Tenisheff, Тенишев Дамир Шамильевич 2003-2008