Skip to content

Latest commit

 

History

History
242 lines (168 loc) · 9.84 KB

l2.md

File metadata and controls

242 lines (168 loc) · 9.84 KB

Указатели

Помним, да, что программируем дома, а изучаем сложные аспекты языка на занятии.

На этом занятии мы разобрали:

  • еще раз - чем характеризуется переменная? Это важно понять и осознать.

    1. Типом данных (int, float, ...) - это означает сколько байт в памяти она занимает и в каком формате хранится (целое число, с плавающей точкой, число без знака, ...).
    2. Своим собственным адресом. Любая переменная, которая создается в памяти, имеет свой собственный адрес.
  • разобрали как создаются массивы и как они хранятся в памяти.

    Что надо запомнить: что имя массива - это указатель. Т.е это переменная, которая хранит в себе ОДИН адрес, как любая другая переменная типа указатель, просто в этой переменной лежит адрес первого элемента из массива.

    Вот в целом хороший туториал этот и этот. Если вы нашли более понятные статьи, то присылайте мне и делитесь с ребятами.

  • еще раз запомнили, что чтобы посмотреть какой адрес у переменной (а у каждой переменной есть адрес и он у нее свой), мы пользуемся операцией &. Например:

int number;
int *pointer;
pointer = &number;

Что тут происходит?
Cоздали целочисленную переменную с именем number. Она располагается по какому-то адресу, например, 1000. Следом создали переменную, которая может хранить в себе адрес целочисленной переменной, pointer. Ее адрес в памяти 1004 (понятно почему?) и ее значение, которая она хранит, будет являтся каким-то адресом. В данном случае мы эту переменную сразу инициализировали pointer = &number. Т.е. операцией & мы узнали адрес у переменной number и положили его в переменную pointer.

Итак, чем характеризуется переменная? Своим типом данных, адресом и что в ней хранится. Описывая переменную pointer мы можем сказать, что ее адрес 1004, а значение, которое в ней лежит, 1000, что является адресом переменной a. Изи! :)
Если кто-то не понимает этого, то не стесняйтесь и спрашивайте.

  • разименовывание. Хорошо, у нас есть переменные, которые хранят в себе адреса других переменных. И? Мы можем обращаться к значениям по этим адресам.
int number = 10;
int *pointer;

printf("\n %d", number); // выведет 10
printf("\n %p", &number); // выведет адрес переменной number
printf("\n %p", &pointer); // выведет адрес переменной pointer, ведь у нее он свой собственный

pointer = &number;
printf("\n %p", &pointer); // собственный адрес pointer не изменился, а вот ее значение?
printf("\n %p", pointer); // а в ней теперь лежит значение адреса переменной number

// теперь мы можем менять значение number, используя переменную pointer
// чтобы поменять значение, по адресу, который лежит в переменной-указателе, мы используем операцию разименования - *

*pointer = 22; // меняем значение, которое нахожилось по адресу, который лежал в pointer
// проверяем
printf("\n %p", &number); // адрес остался тот же
printf("\n %p", &pointer); // тут тоже адрес свой
printf("\n %p", pointer); // в самой переменной-указателе по прежнему лежит адрес переменной number

printf("\n %d", number); // а вот значение переменной изменилось
  • еще способы разименования.
    *pointer == pointer[0] -- *pointer говорит показать значение по адресу, который лежит в этой переменной. pointer[0] говорит покажи мне значение, которое находится от текущего указателя на 0 элементов - т.е. значение самого себя.

Более общий случай: *(pointer + i) == pointer[i]. Слева - прибавь к текущему адресу еще i таких же ячеек и операцией * покажи мне что лежит в этой ячейке. Справа - покажи мне, не меняя адрес pointer, какое значение лежит через i таких же ячеек памяти.

Зачем это? Например, для того, чтобы двигаться по массиву:

int *pointer = new int[10]; // создаем указатель pointer, для него выделяем память из 10 элементов по 4 байта. И в значение ячейки pointer кладем адрес первого элемента из этой выделенной области.

// заполним этот массив, какими-нибудь значениями
for(int i=0; i < 10; i++) {
  pointer[i] = rand() % 100; // это общепринятое обращение к массивам.
}

// но точно также мы могли заполнить его значениями вторым способом
for(int i=0; i < 10; i++) {
  *(pointer + i) = rand() % 100;
}

// но все же общепринято, что с массивами работают предыдущим способом, но если встретите такое, что не думайте, что это ошибка
  • область видимости и время жизни переменной переменной. Тоже разобрали, поняли, что в функциях создаются свои переменные, куда копируются значения и что нужно делать, чтобы их менять. Можно почитать тут

Задачки, которые разобрали.

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

Задание звучало так: какой будет вывод в консоли

Задача 1
#include "stdafx.h"
#include <stdio.h>

void fun(int x) {
	x = 30;
}


int main() {

	int y = 20;
	fun(y);
	printf("%d", y);

	return 0;
}
Задача 2
#include "stdafx.h"
#include <stdio.h>


int main() {

	int arri[] = { 1, 2, 3 };
	int *ptri = arri;

	char arrc[] = { 1, 2, 3 };
	char *ptrc = arrc;

	printf("sizeof arri[] = %d \n", sizeof(arri));
	printf("sizeof ptri[] = %d \n", sizeof(ptri));

	printf("sizeof arri[] = %d \n", sizeof(arrc));
	printf("sizeof ptri[] = %d \n", sizeof(ptrc));

	return 0;
}
Задача 3
#include "stdafx.h"
#include <stdio.h>


int main() {

	float arr[5] = { 12.5, 10.0, 13.5, 90.5, 0.5 };
	float *ptr1 = &arr[0];
	float *ptr2 = ptr1 + 3;

	printf("%f ", *ptr2);
	printf("%d", ptr2 - ptr1);

	return 0;
}
Задача 4
#include "stdafx.h"
#include <stdio.h>


int main() {

	char *ptr = "SiBears Security School";
	printf("%c \n", *&*&*ptr);

	return 0;
}
Задача 5
#include "stdafx.h"
#include <stdio.h>

void fun(int *p) {
	int q = 10;
	p = &q;
}

int main() {

	int number = 20;
	int *p = &number;
	fun(p);
	printf("%d", *p);

	return 0;
}
Задача 6
#include "stdafx.h"
#include <stdio.h>

#define R 10
#define C 20

int main() {

	int (*p)[R][C];
	printf("%d", sizeof(*p));

	return 0;
}
Задача 7
#include "stdafx.h"
#include <stdio.h>

void f(char**);

int main() {
	char *argv[] = {"ab", "cd", "ef", "gh", "ij", "kl"};
	f(argv);

	return 0;
}

void f(char **p) {
	char *t;
	t = (p += sizeof(int))[-1];
	printf("%s\n", t);
}

Это не тривиальные вещи, поэтому не понимать их - в целом нормально. Но! Надо разобраться, поэтому не стесняйтесь задавать вопросы, если что-то недопоняли.


Домашнее задание