C указатель на указатель и передача по ссылке - PullRequest
5 голосов
/ 28 июня 2011

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

Например, следующий код не работает так, как я ожидал:

#include <stdio.h>

int newp(char **p) {
  char d = 'b';
  *p = &d;
  /*printf("**p = %c\n", **p);*/
  return 1;
}

int main() {
  char c = 'a';
  char *p = &c;
  int result;

  result = newp(&p);
  printf("result = %d\n", result);
  printf("*p = %c\n", *p);
  printf("c = %c\n", c);

  return 0;
}

Результат, который я получаю, таков:

result = 1
*p = 
c = a

* p печатает как ничего.Вместо этого я ожидал бы *p = b.

Однако , если я раскомментирую строку 6 (printf в функции newp), то получу следующее:

**p = b
result = 1
*p = b
c = a

Чего мне не хватает?

Ответы [ 4 ]

8 голосов
/ 28 июня 2011

Вы имеете дело с неопределенным поведением.Переменная d является локальной (находится в стеке) и недоступна после возврата включающей функции (newp).

При разыменовании p вне newp адрес в стеке &d может быть перезаписано другой локальной переменной или содержать мусор.

5 голосов
/ 28 июня 2011

Вы сохраняете адрес локальной переменной (d) в *p и затем разыменовываете его, когда переменная выходит из области видимости. Неопределенное поведение

1 голос
/ 28 июня 2011

Возможно, вам не хватает ключевого слова static, например:

int newp(char **p) {
    static char d = 'b';   /* <--- HERE */
    *p = &d;
    /*printf("**p = %c\n", **p);*/
    return 1;
}

Это ключевое слово static заставляет компилятор найти локальную переменную в «статическом хранилище», которое продолжает существовать.(т.е. сохраняет свое значение) в течение периодов времени после вызова newp().Однако существует только одна копия этой памяти - каждый последующий вызов содержащей функцию (newp) повторно использует одну и ту же ячейку памяти и может перезаписать значение в это время.

Без ключевого слова static для определения объявления локальной переменной хранилище будет «автоматическим», что означает, что оно автоматически выгружается из текущего использования после возврата содержащей функции.После возврата newp память, ранее использовавшаяся для локальной переменной, может быть повторно использована для любых целей.

0 голосов
/ 17 марта 2017
#include <stdio.h>

// Here *pointer means that the parameter that this function 
// will expect will be a pointer. 
void changeViaPointer(int *pointer);

// Pointer of a pointer.
void changeViaPointerInBetween(int **pointer);

int main(){

    int number;
    number = 20;

    // Here *pointer means that the variable that is declared will be a pointer.
    int *pointer;

    // Actually asigning value to the pointer variable.
    pointer = &number;

    // Pointer of a pointer.
    int **pointerInBetween;

    // Assigning value to the pointer of a pointer. 
    // Assigning the memory location where this pointer points to. 
    // So this is a pointer in between.
    pointerInBetween = &pointer;

    printf("The number before changing is %d\n", number);

    // Pass the pointer variable.
    changeViaPointer(pointer);
    printf("The number after pointer changing is %d\n", number);

    // Pass the pointer of a pointer variable.
    changeViaPointerInBetween(pointerInBetween);
    printf("The number after pointer in between changing is %d\n", number);

    return 0;
}

void changeViaPointer(int *pointer){

    // Okay, at this point we have received a variable called pointer,
    // which points to some value. In order to access this value
    // we need to use *pointer.
    // BUT THIS IS DIFFERENT FROM THE *pointer IN THE FUNCTION DECLARATION!!!
    *pointer = *pointer + 20;
}

void changeViaPointerInBetween(int **pointer){

    // **pointer explanation:
    // Only pointer is the memory location
    // *pointer  is the value of that memory location, which in this specific case is also a memory location
    // **pointer is the value of what the other pointer points to.
    **pointer = **pointer + 20;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...