1

Доброго времени суток...

    void main()
{
    int a,b,c;
    int *A, *B;
    a = 3;
    b = 5;
    A = &a;
    B = &b;
    c = (A - B);// ???
    printf("c=%d\n", c );//Vs 2015 выдает 3...Почему? 
    printf("num1 = %d num2 = %d\n", *(B + c), *(A - c));
}

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

  • 1
    Разница указателей на 3 - это разница адресов на 3 * sizeof(int) в данном случае. – insolor Feb 19 '18 at 20:32
  • почему 3? Откуда вообще взялось это число? Так исходя из вашего комментария с должно получить 12? (3 * 4)? – Biohazard Feb 19 '18 at 20:40
  • По-моему, это неопределённое поведение. Вычитать указатели можно только в рамках одного массива. https://ru.stackoverflow.com/a/477313/235436 – Кирилл Малышев Feb 19 '18 at 20:49
  • Согласен, точнее с массивом куда более понятно для чего это делается, а в данном случае какой смысл? Вопрос взят из экзамена по си, а значит есть какой либо смысл, ведь дальше идет второй принт...но я не могу понять чему равно (А - В).... для начала.... – Biohazard Feb 19 '18 at 20:54
  • @Biohazard, ну, здесь https://ideone.com/DvKIzL выдаёт -1. Ведь логично, что a и b будут идти друг за другом в памяти. В вашем случае переменная a, видимо, сидит в памяти на 3 * sizeof(int) байт дальше в памяти, чем b. Это ведь неопределённое поведение, неизвестно заранее, как компилятор разместит переменные в памяти. Это гарантируется только в массивах. – Кирилл Малышев Feb 19 '18 at 20:59
  • @КириллМалышев Логично? Мейби , не знаю, т.к я понимаю, что это дело случая... но суть уловил...спасибо. И тогда следует следующий вопрос...что происходит во втором принте...? Если разница двух соседних адресов = -1 то например, В + (-1) куда ведет? и почему там находится 3? – Biohazard Feb 19 '18 at 21:17
  • @Biohazard, http://ibb.co/b869i7. Каждая ячейка - это байт. В этом примере ideone.com/DvKIzL нам повезло, что переменные разместились друг за другом. Этого никто не гарантирует. Так как указатели указывают на int, то их разность будет означать разницу в 4 байтах (если int - 4 байта). Байты в памяти, как правило, расположены в обратном порядке, от младших к старшим. Пугаться этого не надо. Си сам умеет разбираться, как считывать данные. – Кирилл Малышев Feb 19 '18 at 21:29
  • @Biohazard Адресная арифметика производит вычисления в элементах массива, а не в байтах. Рекомендую погуглить на тему "адресная арифметика в Си". – kisssko Feb 19 '18 at 23:52
  • @Biohazard Если нужно, чтобы всё считалось честно в байтах - сразу приводите указатели к uintptr_t, или size_t. Нужно будет подключить stdint.h c = (int)((uintptr_t)A - (uintptr_t)B);// – kisssko Feb 20 '18 at 00:01

2 Answers2

1

В языке С разрешается вычитать друг из друга только указатели на элементы одного и того же массива (и на воображаемый элемент за последним элементом массива). Результат такого вычитания - знаковое количество элементов массива между этими указателями.

Вычитать друг из друга указатели на две независимые переменные - как в вашем случае - неопределенное поведение. Никакого смысла в этом вычитании нет.

0

для чего это делается, а в данном случае какой смысл? ... ведь дальше идет второй принт...но я не могу понять чему равно (А - В)

Смысл операции ВЫЧИТАНИЯ указателей в данном примере заключается в том, что бы продемонстрировать дополнительность операции вычитания по отношению к операции СЛОЖЕНИЯ. Смотрите, что получается во втором операторе printf:

*(B + c) == *(B + (A - B)) == *(B + A - B) == *(A) == *А  
*(A - c) == *(B - (A - B)) == *(B - A + B) == *(В) == *В

Красивый трюк - и ничего более :-)

Sergey
  • 13,474