Подтвердить что ты не робот

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

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

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;
}
4b9b3361

Ответ 1

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

В первом примере вы храните этот адрес в локальной переменной аргумента p, но поскольку это просто аргумент, который не возвращает его в основную программу, потому что 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.

Ответ 2

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

Ответ 3

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

void memory(int*& p, int size)

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

Ответ 4

При первом вызове в память:

void memory(int * p, int size)

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

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

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

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

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

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

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

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

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

Ответ 8

память (p, 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;
    }

Ответ 9

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

#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;
}