почему указатель на указатель необходим для выделения памяти в функции

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

void memory(int * p, int size) {
    try {
        p = (int *) malloc(size*sizeof(int));
    } catch( exception& e) {
        cout<<e.what()<<endl;   
    }
}

это не работает в основной функции ударом

int *p = 0;
memory(p, 10);

for(int i = 0 ; i < 10; i++)
    p[i] = i;

однако, это работает как это.

void memory(int ** p, int size) {               `//pointer to pointer`
    try{
        *p = (int *)    malloc(size*sizeof(int));
    } catch( exception& e) {
        cout<<e.what()<<endl;   
    }
}

int main()
{
    int *p = 0;
    memory(&p, 10);       //get the address of the pointer

    for(int i = 0 ; i < 10; i++)
        p[i] = i;

    for(int i = 0 ; i < 10; i++)
        cout<<*(p+i)<<"  ";

    return 0;
}
15
задан ndim 12 April 2010 в 22:59
поделиться

9 ответов

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

В вашем первом примере вы сохраняете этот адрес в локальной переменной аргумента p , но поскольку это всего лишь аргумент, он не возвращается в основную программу, потому что C / C ++ являются передача по значению по умолчанию - даже для указателей.

Main      Function      malloc

  p         p            allocated
+---+     +---+         
| 0 |     | 0 |           A
+---+     +---+

becomes...

  p         p            allocated
+---+     +---+         
| 0 |     | ------------> A
+---+     +---+

и, таким образом, когда main читает p, он получает 0, а не A.

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

Main      Function      malloc

  p         p            allocated    
+---+     +---+         
| 0 |<------- |           A
|   |     |   |
+---+     +---+

becomes...

  p         p            allocated    
+---+     +---+         
|   |<------- |           
| ----------------------> A
+---+     +---+

и, таким образом, когда main считывает p, он получает A.

50
ответ дан 1 December 2019 в 00:00
поделиться

При первом обращении к памяти:

void memory(int * p, int size)

Осознайте, что вы передаете ЗНАЧЕНИЕ в memory (), а не адрес. Следовательно, вы передаете значение «0» в memory (). Переменная p - это просто копия того, что вы передаете ... in содержит то же значение, но НЕ указывает на тот же адрес ...

Во второй функции , вы передаете ADDRESS вашего аргумента ... поэтому вместо этого p указывает на адрес вашей переменной, а не просто является копией вашей переменной.

Итак, когда вы вызываете malloc следующим образом:

*p = (int *)    malloc(size*sizeof(int));

Вы назначаете возврат malloc значению переменной, на которую указывает p .

Таким образом, ваш указатель действителен за пределами memory ().

2
ответ дан 1 December 2019 в 00:00
поделиться

Я исправил код .. прочтите комментарий, и все будет ясно ..

#include<iostream>
#include<conio.h>
#include<exception>

using namespace std;


void memory(int* p, int size) {               //pointer to pointer` not needed
    try{
        p = new int[size] ;
    } catch(bad_alloc &e) {
       cout<<e.what()<<endl;   
    }
}

int main()
{
    // int *p = 0;  wrong .. no memory assigned and then u are passing it to a function
    int *p;
    p = new int ;  // p = malloc( sizeof(int));
    /*before using a pointer always allocate it memory else
     you ll get frequent system crashes and BSODs*/
    memory(p, 10);       //get the address of the pointer

    for(int i = 0 ; i < 10; i++)
        p[i] = i;

    for(int i = 0 ; i < 10; i++)
        cout<<*(p+i)<<"  ";

    getch();    
    return 0;
}
-1
ответ дан 1 December 2019 в 00:00
поделиться

вам не нужно использовать указатель на указатель, а использовать указатель, на который имеется ссылка, т.е. *, а не просто *

0
ответ дан 1 December 2019 в 00:00
поделиться

Первый пример не работает, потому что параметр указателя не является указателем в main, он просто содержит то же значение.

1
ответ дан 1 December 2019 в 00:00
поделиться

В Си у вас есть только передача по значению. Поэтому ваша функция memory() получает свою собственную локальную копию p. malloc внутри memory() присваивает только той копии p, которая является локальной для функции. Когда memory() возвращается в main(), копия p из main остается неизменной. В C++ для решения этой проблемы используется передача по ссылке, например, так:

void memory(int*& p, int size)

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

3
ответ дан 1 December 2019 в 00:00
поделиться

Указатель хранит адрес, по которому хранятся данные. Передача указателя на функцию означает присвоение ей адреса данных . Однако здесь у вас нет адреса для данных до вызова malloc . Поэтому вместо этого вам нужно передать адрес указателю (т.е. указатель на указатель). Это позволяет памяти принимать адрес указателя p и устанавливать p для указания области памяти, которая выделяется для данных.

7
ответ дан 1 December 2019 в 00:00
поделиться

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

Есть три способа вернуть это значение (2, если вы используете C):

  • использовать указатель, здесь это указатель на указатель
  • использовать ссылку, здесь это ссылка на указатель
  • используйте возвращаемое значение функции, поэтому заставьте память возвращать int * вместо void

Третий способ определенно мне больше нравится.

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

0
ответ дан 1 December 2019 в 00:00
поделиться

память (стр, 10); // получаем адрес указателя

, это просто отправляет значение p, а не адрес p. он отправляет (* p). если добавлены p 123 и его значение 50, он отправляет 50 функции.

и в функции памяти он создает новый указатель с новым адресом, например 124, и он содержит 50; и он выделит память и запишет начало выделенной памяти в 124, а не в 123, поэтому p в главном по-прежнему содержит 50. Итак, вы ничего не сделали !. Вы можете контролировать это с помощью этого кода.

     #include<iostream>
    #include<conio.h>
    #include<exception>

    using namespace std;


    void memory(int* p, int size) {               //*************pointer to pointer` is a must**********
        try{
            p = new int[size] ;
            p[0]=100;
        } catch(bad_alloc &e) {
           cout<<e.what()<<endl;   
        }
    }

    int main()
    {
         int *p = 0;  ******you can do you should do this*******
        p = new int ; 
/* p = malloc( sizeof(int)); // this just change the value inside of p it is unnecessary 
and you will lose a adress from memory :) and possibly it will be unsafe if you free p may, you just 
free one adress*/
        /*before using a pointer always allocate it memory else
         you ll get frequent system crashes and BSODs*/
        memory(p, 10);       //get the address of the pointer//you are getting nothing
        cout <<p[0];
        //we set p[0] to 100 but it will write a garbage value here. 
        //because the value inside of p didn't change at the memory function
        //we sent just the value inside of p.

        getch();    
        return 0;
    }
0
ответ дан 1 December 2019 в 00:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: