Сохранить значение указателя - PullRequest
4 голосов
/ 11 января 2011

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

int *ptr;

void allocateMemory(int *pointer)
{
     pointer = malloc(sizeof(int));
}

allocateMemory(ptr);

Еще одна вещь, а именно, как я могу выделить память для 2 или более размерных массивов? Не по индексу, а по арифметике указателей. Это:

int array[2][3];
array[2][1] = 10;

так же, как:

int **array;
*(*(array+2)+1) = 10

Кроме того, почему я должен передавать в памяти адрес указателя на функцию, а не сам указатель. Например:

int * a;

почему бы и нет:

allocateMemory(*a) 

но

allocateMemory(a)

Я знаю, что всегда должен это делать, но я действительно не понимаю, почему. Пожалуйста, объясните мне.

Последнее, в указателе вот так:

int *a;

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

printf("Is this address of integer it is pointing to?%p\n",a);
printf("Is this address of the pointer itself?%p\n",&a);

Ответы [ 5 ]

10 голосов
/ 11 января 2011

Я постараюсь заняться этим по очереди:

  1. Теперь я хочу, чтобы реальный указатель был изменен без необходимости возвращать указатель из функции.

    Вам нужно использовать еще один слой косвенности:

    int *ptr;
    
    void allocateMemory(int **pointer)
    {
        *pointer = malloc(sizeof(int));
    }
    
    allocateMemory(&ptr);
    

    Вот хорошее объяснение из comp.lang.c FAQ .

  2. Еще одна вещь, а именно, как я могу выделить память для 2 или более размерных массивов?

    Одно выделение для первого измерения, а затем цикл выделений для другого измерения:

    int **x = malloc(sizeof(int *) * 2);
    for (i = 0; i < 2; i++)
        x[i] = malloc(sizeof(int) * 3);
    

    Опять же, здесь является ссылкой на этот точный вопрос из comp.lang.c FAQ .

  3. Это:

    int array[2][3];
    array[2][1] = 10;
    

    так же, как:

    int **array;
    *(*(array+2)+1) = 10
    

    АБСОЛЮТНО НЕ. Указатели и массивы разные. Однако вы можете иногда использовать их взаимозаменяемо. Ознакомьтесь с этими вопросами из comp.lang.c FAQ .

  4. Кроме того, почему я должен передавать в памяти адрес указателя на функцию, а не сам указатель?

    почему бы и нет:

    allocateMemory(*a) 
    

    Это две вещи - C не имеет обходной ссылки, кроме случаев, когда вы реализуете это самостоятельно, передавая указатели, и в этом случае также потому, что a еще не инициализирован - если вы хотите разыменовать его, Вы бы вызвали неопределенное поведение. Эта проблема аналогична этому , найденному в comp.lang.c FAQ .

  5. int *a;
    

    Адрес памяти, содержащий фактическое значение, или адрес памяти указателя?

    Этот вопрос на самом деле не имеет смысла для меня, но я постараюсь объяснить. a (при правильной инициализации - вашего примера здесь нет) - это адрес (сам указатель). *a - это объект, на который указывают - в этом случае это будет int.

  6. Кстати, при печати такой указатель выглядит так:

    printf("Is this address of integer it is pointing to?%p\n",a);
    printf("Is this address of the pointer itself?%p\n",&a);
    

    Правильно в обоих случаях.

1 голос
/ 11 января 2011

Чтобы ответить на ваш первый вопрос, вам нужно передать указатель на указатель.(int**)

Чтобы ответить на второй вопрос, вы можете использовать этот синтаксис для доступа к местоположению в существующем массиве.
Однако вложенный массив (int[][]) не совпадает суказатель на указатель (int**)

Чтобы ответить на ваш третий вопрос:

Запись a передает значение переменной a, которая является адресом памяти.
Запись *a передает значение , указанное в , переменной, которая является фактическим значением, а не адресом памяти.

Если функция принимает указатель, это означает, что она хочет адрес, а не значение.
Следовательно, вам нужно передать a, а не *a.
Было бы aуказатель на указатель (int**), вы должны передать *a, а не **a.

0 голосов
/ 11 января 2011

Обратите внимание, что возврат указателя или принуждение вызывающего абонента к перемещению указателя в переменной void * temp является только способом, которым вы можете использовать тип void *, чтобы разрешить вашей функции работать с разными типами указателей. char **, int ** и т. Д. Не конвертируются в void **. Таким образом, я бы советовал против того, что вы пытаетесь сделать, и вместо этого используйте возвращаемое значение для функций, которые должны обновлять указатель, если ваша функция по дизайну не работает только с определенным типом. В частности, простые malloc оболочки, которые пытаются изменить интерфейс для передачи указателей на указатели, по своей сути нарушены.

0 голосов
/ 11 января 2011

Я думаю, вы немного озадачены тем, что на самом деле является указателем.
Указатель - это просто переменная, значение которой представляет адрес в памяти. Поэтому, когда мы говорим, что int *p - указатель на целое число, это просто означает, что p - это переменная, которая содержит число, которое является адресом памяти int.
Если вы хотите, чтобы функция выделяла буфер целых чисел и изменяла значение в переменной p, этой функции необходимо знать, где в памяти хранится p. Таким образом, вы должны дать ему указатель на p (т. Е. Адрес памяти p), который сам по себе является указателем на целое число, поэтому для функции требуется указатель на указатель на целое число (т. Е. адрес памяти, где функция должна хранить число, которое, в свою очередь, является адресом памяти целых чисел, выделенных функцией), поэтому

void allocateIntBuffer(int **pp)
{
    // by doing "*pp = whatever" you're telling the compiler to store
    // "whatever" not in the pp variable but in the memory address that
    // the pp variable is holding.
    *pp = malloc(...);
}

// call it like
int *p;
allocateIntBuffer(&p);

Я думаю, ключом к вашим вопросам является понимание того, что в переменных-указателях нет ничего особенного. Указатель - это переменная, как и любая другая, только то значение, которое хранится в этой переменной, используется для представления позиции в памяти.

0 голосов
/ 11 января 2011

Ваш первый вопрос:

Вы можете передать адрес указателя:

void allocateMemory(int **pointer) {
    *pointer = malloc(sizeof(int));
}

int *ptr;
allocateMemory(&ptr);

или вы можете вернуть значение указателя:

int *allocateMemory() {
    return malloc(sizeof(int));
}

int *ptr = mallocateMemory();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...