2015-08-19 3 views
4

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

int nums[] = {1, 2, 3}; 

nums является переменной массива и действует как указатель, который указывает на первую ячейку памяти массива. Я написал следующий код, и я пытаюсь понять, почему я получаю результаты, которые я получаю:

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    int nums[] = {1, 2, 3}; 

    if(nums == &nums) 
    puts("nums == &nums"); 
    else 
    puts("nums != &nums"); 

    if((nums + 1) == (&nums + 1)) 
    puts("(nums + 1) == (&nums + 1)"); 
    else 
    puts("(nums + 1) != (&nums + 1)");  

    printf("nums: %i\n", nums); 
    printf("&nums: %i\n", &nums); 
    printf("nums + 1: %i\n", nums + 1); 
    printf("&nums + 1: %i\n", &nums + 1); 

    return 0;  
} 

Я получаю, что nums == &nums верно, как и ожидалось; однако, когда я применяю арифметику указателя и добавляю 1 в nums, этот результат не равен &nums + 1. Другими словами (nums + 1) != (&nums + 1), хотя nums == &nums.

Это выход из программы, которую я получаю:

nums == &nums 
(nums + 1) != (&nums + 1) 
nums: 2345600 
&nums: 2345600 
nums + 1: 2345604 
&nums + 1: 2345612 

Оказывается, что nums и nums + 1 выключены устанавливается на 4 байта; однако &nums и &nums + 1 смещены на 12. Почему это смещение составляет 12 байтов, а не 4?

+0

Кстати, вам может потребоваться использовать значения '% p' для printf. – Nayuki

+1

Возможный дубликат [Итак, вы думаете, что знаете указатели?] (Http://stackoverflow.com/questions/232303/so-you-think-you-know-pointers) –

ответ

7

Путаница связана с тем, как в C массивы неявно распадаются на указатели в определенных контекстах.

Проще объяснить, nums + 1 эффективно означает &nums[0] + 1. nums[0] - это тип int, который составляет 4 байта на элемент. Таким образом, &nums[0] + 1 составляет 4 байта после &nums.

Что касается &nums + 1, &nums имеет тип int(*)[3], который составляет 12 байт на элемент. Таким образом, &nums + 1 составляет 12 байт после &nums.

+0

Интересно, это означало бы, что если бы я хотел получить следующее место памяти сразу после массива я мог бы использовать «& nums + 1». Спасибо за быстрый ответ. –

+1

Да, это правда.Однако вы не можете использовать эту ячейку памяти, потому что она будет вызывать * неопределенное поведение *. Вы также не можете вычислять любые места памяти в конце. – Nayuki

2

Оба выражения, (int*) nums и &nums имеют типы указателей, но указанные типы различны. Вы можете проверить их только на C, а не на C++.

Тип nums является int[3], то есть, «массив из 3-х объектов типа int» и типа (int*) nums является int*, то есть «указатель на int». Добавление 1 в (int*) nums означает получение указателя на объект типа int, который следует за nums[0]. В терминах адресов это означает добавление 1 * sizeof (int).

Тип &nums: int(*)[3], то есть 'указатель на массив из 3 объектов типа int'. Добавление 1 в &nums означает получение указателя на объект типа int[3], который следует за nums. В терминах адресов это означает добавление 1 * sizeof (int[3]), то есть 3 * sizeof (int).

Смежные вопросы