2016-02-18 2 views
1

Я пытаюсь использовать арифметику указателя для доступа к местоположениям указателей, таким как массив. Для тестирования я написал ниже код.Атрибут указателя работает, но указатель de-referencing не работает

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

С моими знаниями о C и указателях до сих пор, я не могу объяснить, почему указатель не работает. Если бы я не смог получить увеличенное местоположение/адрес указателя, то по крайней мере я бы понял, что арифметика указателя не работает, но когда она работает, то почему указатель де-ссылки не работает.

Код:

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

int **DoublePtr; 

void doublePointerTest(); 

int main(void) 
{ 
    doublePointerTest(); 
} 

void doublePointerTest() 
{ 
    DoublePtr = malloc(sizeof(int*)); 
    *DoublePtr = malloc(sizeof(int) * 10); 

    printf("Address of DoublePtr = %p\n", DoublePtr); 
    printf("Address of *DoublePtr = %p\n", *DoublePtr); 

    **DoublePtr = 100; 

    *DoublePtr += 1; 
    printf("+1 Address of *DoublePtr = %p\n", *DoublePtr); 
    **DoublePtr = 1; 

    *(*DoublePtr += 1) = 2; 
    printf("+2 Address of *DoublePtr = %p\n", *DoublePtr); 
    //**DoublePtr = 2; 

    *DoublePtr += 1; 
    printf("+3 Address of *DoublePtr = %p\n", *DoublePtr); 
    **DoublePtr = 3; 

    // *DoublePtr[4] = 4; 
    // *DoublePtr[8] = 8; 
    // *DoublePtr[3] = 3; 
    // *DoublePtr[2] = 2; 

    for(int i = 0; i < 10; i++, *DoublePtr += 1) 
    { 
     printf("%d. ", i); 
     printf("%d\n", **DoublePtr); 
    } 
} 

O/P:

[email protected] (~/psets/pset5/pset5_working): clang testing.c -o testing 
[email protected] (~/psets/pset5/pset5_working): ./testing 
Address of DoublePtr = 0x8cd4008 
Address of *DoublePtr = 0x8cd4018 
+1 Address of *DoublePtr = 0x8cd401c 
+2 Address of *DoublePtr = 0x8cd4020 
+3 Address of *DoublePtr = 0x8cd4024 
0. 3 
1. 0 
2. 0 
3. 0 
4. 0 
5. 0 
6. 0 
7. 0 
8. 135105 
9. 0 
[email protected] (~/psets/pset5/pset5_working): 


Обновления:

Согласно комментариям и ответ, исправил мой код с DoublePtr = malloc(sizeof(int)); до DoublePtr = malloc(sizeof(int*)); и протестирован, но он дает тот же результат.

+0

@AlterMann Тестирование, но такой же результат. – hagrawal

+0

В отчетах printf в «Адресе» следует указать «Значение». Вы печатаете адрес указываемого объекта, а не адрес указателя. –

+0

Записанные строки '* DoublePtr [4]' также будут переполнением буфера, вы, вероятно, имели в виду '(* DoublePtr) [4]' –

ответ

3

Ваш код записывает 100,1,2,3 в первые 4 местоположения 10 вас malloc.

Затем вы распечатываете содержимое следующих 10 мест, начиная с 3: вы видите 3, затем 6 неинициализированных значений, а затем переполнение буфера.

Вы никогда не печатаете значения первых трех местоположений. Ваше разыменование для установки значения работает, но вы никогда не выдаете результат.

Возможно, вы хотели установить *DoublePtr до его первоначального значения перед печатью?

+0

Спасибо за ваши приятели, вы прибиты довольно много, но я все еще не ожидаю o/p. Я использовал временную переменную для хранения двойного указателя «int ** tempDoublePtr = DoublePtr;», а затем использовал этот 'tempDoublePtr' в FOR, но все еще не работает, я сделал что-то неправильно? – hagrawal

+0

@hagrawal Да, вы должны использовать 'int * tempPtr = * DoublePtr;', а затем использовать 'tempPtr' в цикле. Сохранение 'DoublePtr' бесполезно, поскольку значение DoublePtr' не изменилось; это '* DoublePtr', который изменился. На самом деле было бы лучше оставить '* DoublePtr' неизменным и использовать' tempPtr' всякий раз, когда вы хотите иметь подвижный указатель. –

+0

Вы пригвоздили его помощника, вы действительно прибили его. Большое спасибо. – hagrawal

3

В коде

DoublePtr = malloc(sizeof(int)); 

неправильно. Вы в конечном итоге выделяете неправильный объем памяти. Вы должны изменить его

DoublePtr = malloc(sizeof(int*)); 

или, лучше,

DoublePtr = malloc(sizeof *DoublePtr); 

Кроме того, всегда проверять возвращаемое значение malloc(), чтобы обеспечить успех, прежде чем использовать возвращенный указатель.

Это еще одна проблема: вы проигнорировали побочный эффект использования +=. Он фактически изменяет содержимое левого операнда. Таким образом, ваш *DoublePtr увеличивается каждый раз, когда вы используете +=.

После этого, не переустанавливая его на исходный указатель начала, вы продолжаете делать += на нем в более позднем цикле. Это вызывает два сложенных Issue

  1. As malloc() возвращается неинициализированная памятью, в цикле, вы пытаетесь читать все неинициализированной памяти, вызывающую undefined behavior.
  2. Поскольку вы не сбросили указатель, после 6-й итерации вы фактически выходите за пределы, что снова вызывает UB.
+0

Тестирование, но тот же результат. – hagrawal

+0

@hagrawal обновил мой ответ. –

+0

"* Таким образом, ваш * DoublePtr увеличивается каждый раз, когда вы используете + = на нем.« Это то, что я пытаюсь сделать, так я хочу получить доступ к указателю, точно так же, как массив, используя арифметику указателя .. @ М. M дал правильное направление. – hagrawal

1

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

int* pointer = malloc(sizeof(int) * 10); 
int** DoublePtr = &pointer; 

ИЛИ

int DoublePtr = &malloc(sizeof(int) * 10); 

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

+0

Спасибо, что приятель за ваше время ответить. – hagrawal

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