LINUX.ORG.RU

c99, передача указателей в функции


0

2

У меня есть код, похожий на этот:

#include <stdlib.h>
#include <stdio.h>

void y(int * restrict a,int *restrict b){
   if (1)
      a = (int*)malloc(sizeof(int));

}

void x(int *restrict a, int *restrict b){
   y(a, b);
}

int main(){
int * a = NULL, * b = NULL;
x(a, b);
printf(«%p\n», a);
   return 0;
}

Я ожидаю, что принтф мне выведет адрес в памяти, но он выводит (nil). Начинаю подумывать, что упустил что-то в основах. Как правильно передавать указатели и получать значения из них?



Последнее исправление: Yoda_The_Master (всего исправлений: 1)

всё правильно выводит

1) указатели вообще-то копируются при передаче

2) нефиг malloc'и по функциям прятать

shty ★★★★★
()

voyd y ничего полезного делать не будет. Так же, как и void x :)

Передавайте указатель на указатель.

Eddy_Em ☆☆☆☆☆
()

тебе нужны указатели на указатели

DELIRIUM ☆☆☆☆☆
()

Более удачный пример:

#include <stdio.h>
#include <stdlib.h>

void mystery(int *our_ptr) {
    our_ptr = (int *)malloc(sizeof(int));
}

int main(void) {
    int *ptr = NULL;
    mystery(ptr);
    printf("%p\n",(void *)ptr);
    return 0;
}
Когда функция mystery начинает выполняться, создается указатель на целое число our_ptr, равный значению ptr (тоесть NULL). Дальше мы работаем с our_ptr, про существование ptr наша функция не знает. Эта строчка:
our_ptr = (int *)malloc(sizeof(int));
Присваивает указателю our_ptr значение, возвращенное функцией malloc. При этом указатель ptr по прежнему остается равным NULL.

Для того чтобы иметь возможность изменить значение ptr — нужно передать функции mystery адрес ptr, разыменовать его и присвоить ему значение, которое возвратит malloc. Как-то так:

#include <stdio.h>
#include <stdlib.h>

void mystery(int **pptr) {
    *pptr = (int *)malloc(sizeof(int));
}

int main(void) {
    int *ptr = NULL;
    mystery(&ptr);
    printf("%p\n",(void *)ptr);
    return 0;
}

edigaryev ★★★★★
()

>Я ожидаю, что принтф мне выведет адрес в памяти, но он выводит (nil). Начинаю подумывать, что упустил что-то в основах.

Да.

Dimanc ★★
()
Ответ на: комментарий от anon_666

указатели вообще-то копируются при передаче

Более того, все параметры функций передаются по значению.

дык, даже указатель на указатель передаётся по значению :) и все это знают, но почему-то именно с передачей указателей начинаются самые большие проблемы в осознании этого факта у людей, и зачастую тут кроется тяжёлое наследие С++ с его передачами по ссылкам :)

shty ★★★★★
()
Ответ на: комментарий от Eddy_Em

Думаю, стоит еще добавить, что прочитавший K&R такое вытворять не будет :)

не думаю что люди писавшие дрова в linux kernel настолько дремучи, а ведь пишут :)

shty ★★★★★
()
Ответ на: комментарий от shty

не думаю что люди писавшие дрова в linux kernel настолько дремучи, а ведь пишут :)

Вы в каком-нибудь модуле видели подобную глупость?

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от true_admin

Указывает компилятору, что данные, доступные по указателю не перекрываются. Так же, указатель является единственным способом доступа к данным. Вроде так.

Yoda_The_Master
() автор топика
Ответ на: комментарий от Eddy_Em

>Да, а нафига в y переменная b?

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

Yoda_The_Master
() автор топика
Ответ на: комментарий от edigaryev

Потрясающий ответ :) Я нечто подобное и ожидал увидеть.
Всем мои благодарности за решение вопроса)

Yoda_The_Master
() автор топика
Ответ на: комментарий от Eddy_Em

не думаю что люди писавшие дрова в linux kernel настолько дремучи, а ведь пишут :)

Вы в каком-нибудь модуле видели подобную глупость?

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

shty ★★★★★
()
Ответ на: комментарий от shty

нашёл пример, смотрим

static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
 {
         const struct ata_port_info *ppi[] = { &vt6420_port_info, NULL };
         struct ata_host *host;
         int rc;
 
         rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
         if (rc)
                 return rc;
         *r_host = host;
 
         rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
         if (rc) {
                 dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n");
                 return rc;
         }
 
         host->ports[0]->ioaddr.scr_addr = svia_scr_addr(host->iomap[5], 0);
         host->ports[1]->ioaddr.scr_addr = svia_scr_addr(host->iomap[5], 1);
 
         return 0;
 }

взято отсюда

shty ★★★★★
()
Ответ на: комментарий от shty

И что вам здесь не нравится? Все правильно сделано. Никаких попыток вернуть копию указателя не делается. В коде нет попытки изменить значение pdev, так что все ОК.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

И что вам здесь не нравится?

кто сказал «не нравится»? :)

В коде нет попытки изменить значение pdev, так что все ОК.

смотрим на r_host и способ его передачи

shty ★★★★★
()
Ответ на: комментарий от Eddy_Em

эм, я кажется понял суть наших с Вами разногласий: Вы в исходном посте апеллировали к первой части, а я ко второй :)

shty ★★★★★
()
Ответ на: комментарий от shty

нормальный код Вы привели выше часто передается указатель на указатель для инициализации нужная вещь вот еще пример

node* bstree_add_node(node **root, data){
    if (!*root){
        node *new = malloc
        *root = new
        return ...unwind... new;
    }
    if (pfnCmp(data, (*root).data) < 0)
        return bstree_add_node(&(*root).left, data);
    if (pfnCmp(data, (*root).data) > 0)
        return bstree_add_node(&(*root).right, data);
    return NULL;
}


osox
()
Ответ на: комментарий от shty

смотрим на r_host и способ его передачи

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

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от anonymous

>сегодня день передачи указателей на лоре?

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

ttnl ★★★★★
()
Ответ на: комментарий от Yoda_The_Master

не то что бы я эксперт в C, но вот не уверен что стоит пихать к каждой переменной кучу модификаторов типа extern static const auto volatile register restrict signed int *a :)

true_admin ★★★★★
()
Ответ на: комментарий от Eddy_Em

смотрим на r_host и способ его передачи

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

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

shty ★★★★★
()
Ответ на: комментарий от Eddy_Em

ничего подобного :). Ты же не имеешь в виду auto? Остальные вполне боевые :). Ну может restrict не допилен, не проверял...

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

auto вообще не имеет смысла; register выполняется по решению компилятора; volatile имеет смысл лишь для embedded-систем; про restrict не знаю, возможно компилятор и «слушается» эту директиву.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

не-не-не, volatile ещё как имеет смысл при тредах и работе с оборудованием. http://alenacpp.blogspot.com/2006/04/volatile.html

register выполняется по решению компилятора

Конечно, регистров-то мало. Но пока их хватает всё работает как ожидается, проверил.

auto это наследие прошлого, остальное всё используется.

true_admin ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.