почему указатель на указатель необходим для выделения памяти в функции - PullRequest
16 голосов
/ 13 апреля 2010

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

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;

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

Ответы [ 9 ]

50 голосов
/ 13 апреля 2010

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

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

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.

7 голосов
/ 13 апреля 2010

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

3 голосов
/ 13 апреля 2010

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

void memory(int*& p, int size)

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

2 голосов
/ 13 апреля 2010

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

void memory(int * p, int size)

Поймите, что вы передаете VALUE в память (), а не в адрес. Следовательно, вы передаете значение '0' в memory (). Переменная p - это просто копия того, что вы передаете ... in, содержит то же значение, но NOT указывает на тот же адрес ...

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

Итак, когда вы вызываете malloc так:

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

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

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

1 голос
/ 13 апреля 2010

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

0 голосов
/ 01 июля 2010

память (стр. 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 голосов
/ 13 апреля 2010

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

#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;
}
0 голосов
/ 13 апреля 2010

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

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

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

Третий путь определенно имеет мои предпочтения.

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

0 голосов
/ 13 апреля 2010

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

...