Я пересматриваю свои навыки C и изо всех сил пытаюсь понять некоторые моменты. Вот мое понимание C и указателей.

Каждый раз, когда я объявляю переменную, C сохраняет значение в памяти.

int num = 12; // The 12 is stored somewhere in memory, let's say has address 0x54

Чтобы получить адрес памяти переменной num, мы делаем:

printf("%p", &num); // this returns the 0x54

Если я хочу создать указатель, указывающий на то же значение «num», я делаю:

int *ptr = # // create a pointer and point him to 0x54

Если я проверю оба адреса:

printf("%p\n", &num); // prints 0x54
printf("%p\n", ptr); // prints 0x54
printf("%p\n", &ptr); // prints 0x94 is the address of the pointer itself

После вышеуказанного ... Я не понимаю результат своей программы. Я читаю эту книгу, и автор говорит, что мы можем рассматривать указатели как массивы и наоборот (за исключением некоторые случаи [если я правильно понял]).

int ages[] = { 23, 43, 12, 89, 2 };

printf("1-%d\n", ages[0]);
printf("1-%d\n", ages[1]);

printf("2-%p\n", &ages[0]);
printf("2-%p\n", ages);
printf("2-%p\n", &ages);

printf("3-%d\n", *(&ages[1]));
printf("4-%p\n", *(&ages));
printf("5-%p\n", &ages[1]);
printf("6-%p\n", &ages+1);
printf("7-%d\n", *(*(&ages)+1));
printf("8-%ld\n", sizeof(1));

Вывод с вопросами в комментариях:

1-23 // value of position 0, OK
1-43 // value of position 1, OK
2-0x7fff1fd500f0 // adress of the beginning of array, OK
2-0x7fff1fd500f0 // same as above, OK
2-0x7fff1fd500f0 // because ages is not a pointer, same as above, OK
3-43 // get address of ages, advance 4 bytes and then give me the value that is in that address, OK
4-0x7fff1fd500f0 // give me the address of ages, and then give the value that is in that address. The address I have in the print number 2, why doesn't return the value and show me the address? **NOT OK**
5-0x7fff1fd500f4 // give me the address of the position 1 of the array, the address that contains the number 43, OK
6-0x7fff1fd50104 // why I don't get the same number of the print 5? How I jump from f0 to 104? **NOT OK**
7-43 // why I need pointer of pointer, **NOT OK**
8-4 // this was just trying to understand print 6, OK

Может ли кто-нибудь объяснить мне отпечатки 4, 6 и 7 и сообщить, правильно ли я думаю о других отпечатках.

1
user1845593 6 Сен 2016 в 02:59

4 ответа

Лучший ответ

Все ваши замешательства сводятся к двум вещам: как работает приоритет операторов и что означает &ages.

Давайте сначала посмотрим на последнее. Очевидно &ages - указатель. Но что это за указатель на ? Это не указатель на int. Вместо этого это указатель на тип int[5].

Итак, давайте посмотрим на это:

printf("4-%p\n", *(&ages));

Если у вас есть указатель на int[5] и вы используете на нем *, вы получите то, на что он указывает: int[5]. Затем он распадается на указатель при передаче в printf. В частности, указатель на первый элемент массива.

Этот:

printf("5-%p\n", &ages[1]);

Это вопрос приоритета оператора. Используя явные скобки, это &(ages[1]); [] имеет более высокий приоритет, чем &. Что ж, мы знаем, что ages[1] - это второй int в массиве. Использование & на нем вернет указатель на второй элемент в массиве.

Подобным образом:

printf("6-%p\n", &ages+1);

Приоритет оператора говорит нам, что это действительно (&ages) + 1. И помните, что такое &ages? Правильно, указатель на int[5].

Когда мы выполняем арифметические операции с указателями, мы добавляем размер объекта, на который указывается, к адресу. Этот объект - int[5], размер которого равен 20. Или в шестнадцатеричном формате 0x14. Следовательно, вы получаете адрес 0x14 байтов от начала массива.

Что касается:

printf("7-%d\n", *(*(&ages)+1));

Приоритет оператора говорит нам, что это выражение действительно *((*(&ages)) + 1). Таким образом, вы получаете указатель на int[5], снова превращаете его в int[5], а затем добавляете к нему 1. Для этого нужно преобразовать int[5] в int*, а затем использовать арифметику с указателями. Затем вы получаете доступ к значению по этому адресу.

2
Nicol Bolas 6 Сен 2016 в 00:33

Указатель - это не просто адрес, это адрес со связанным типом, который имеет размер.

Таким образом, когда вы увеличиваете указатель на тип массива, он пропускает весь массив.

Другая проблема в коде - распад массива, когда выражение, обозначающее массив, такое как a или *&a, распадается на указатель на первый элемент массива.

Это неудачное неявное преобразование, имевшее смысл во времена раннего C.

В C ++ это вызывает много проблем.

0
Cheers and hth. - Alf 6 Сен 2016 в 00:14

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

Указатель - это переменная некоторого типа, у которой есть адрес и тип данных, на которые она указывает, например:

//int* iPtr = 7; error pointers stores addresses not values
int* iPtr = 0x00000000 //(NULL) points to this address (correct);

Над указателем указывает на целое число, инициализируется, чтобы указать на 0x00000000, который равен NULL

int a  = 7;
int* iPtr = &a;
cout << "a: " << a << endl; // printing value of a; result is a: 7
cout << "&a: " << &a << endl; // printing address of a: result is: &a: 0x0018FF44
cout << "iPtr: " << iPtr << endl; // printing the address iPtr points to as you guess it is the address of a so the result: iPtr: 0x0018FF44

cout << "*iPtr: " << *iPtr << endl; // printing the value stored in the address the iPtr points to so the result is as you guess: *iPtr: 7

Мощное использование указателей: они слишком гибкие, но опасные, они могут указывать на массив, переменную, изменять адрес, размер во время выполнения ... они используются связным списком, oop (полиморфизм ...)

*** не связывайтесь с указателями

0
Raindrop7 6 Сен 2016 в 01:04

Для №4 это, вероятно, результат оптимизации компилятора. Принятие адреса с последующим немедленным разыменованием результирующего указателя фактически является бездействием, поэтому оптимизатор, скорее всего, просто исключит эти операции, оставив в качестве аргумента только ages и это значение, которое вы видите.

Для №6 вы находите адрес массива ages и добавляете к нему 1, что в арифметике с указателями означает «прибавить 1 * размер указанной переменной». Массив из 5 элементов, предполагающий 4-байтовые целые числа, имеет длину 20 байтов, и если вы отметите 0x7FFF1FD500F0 + 0x14, вы получите результат 0x7FFF1FD50104, который вы видите.

Массив - это точно не указатель. Он действует во многом как один, но & (age) не идентичен & (age [0]). Оба имеют одинаковое кажущееся значение, но первое является указателем на 4-байтовое целое число, а второе - указателем на 20-байтовый массив 4-байтовых целых чисел. Вы должны иметь это в виду при работе с указателями на элементы массива, не забывая принимать адрес элемента, когда вы хотите работать с массивом и вам, например, нужно. адрес элемента 0 массива, а не адрес самого массива.

-1
Todd Knarr 6 Сен 2016 в 00:14