Помним, да, что программируем дома, а изучаем сложные аспекты языка на занятии.
На этом занятии мы разобрали:
-
еще раз - чем характеризуется переменная? Это важно понять и осознать.
- Типом данных (int, float, ...) - это означает сколько байт в памяти она занимает и в каком формате хранится (целое число, с плавающей точкой, число без знака, ...).
- Своим собственным адресом. Любая переменная, которая создается в памяти, имеет свой собственный адрес.
-
разобрали как создаются массивы и как они хранятся в памяти.
Что надо запомнить: что имя массива - это указатель. Т.е это переменная, которая хранит в себе ОДИН адрес, как любая другая переменная типа указатель, просто в этой переменной лежит адрес первого элемента из массива.
Вот в целом хороший туториал этот и этот. Если вы нашли более понятные статьи, то присылайте мне и делитесь с ребятами.
-
еще раз запомнили, что чтобы посмотреть какой адрес у переменной (а у каждой переменной есть адрес и он у нее свой), мы пользуемся операцией
&
. Например:
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);
}