Как передать указатель и выделить место в куче - PullRequest
0 голосов
/ 28 октября 2011

Я пытаюсь доставить указатель на функцию, которая затем заполняет ее содержимым, чтобы вызывающая функция могла его использовать. Поскольку это всегда давало мне странные вещи в вызывающей функции, я написал простое представление о том, что я сделал:

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

void bla(char *t)
{
    t = (char*) malloc(5);
    if (t != 0) {
        t[0] = 'h';
        printf("%c\n", t[0]);
    }
}

int main(int argc, char **argv)
{
    char b[10];

    bla(b);
    printf("%c\n", b[0]);
    return 1;
}

Я не совсем уверен, что если он что-то делает, С передает копию аргумента. Нужно ли передавать указатель на указатель или есть лучшее решение?

EDIT:

Извините, ребята, но я не понял. Не могли бы вы просмотреть этот пример:

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

void blub(char **t)
{
    printf("%d\n", *t);
    *t = (char*) malloc(sizeof(char) * 5);
    *t[0] = 'a';
    *t[1] = 'b';
    printf("%d\n", *t);
    printf("%d\n", *t[0]);
    printf("%d\n", *t[1]);
}

int main(int argc, char **argv)
{
    char *a;
    blub(&a);
    printf("%d\n", a);
    printf("%d\n", a[0]);
    printf("%d\n", a[1]);

    return 1;
}

Вывод выглядит следующим образом:

./main
6154128
140488712
97
98
140488712
97
0      <== THIS SHOULD BE 98 AS ABOVE!?

Почему я получаю 98 в функции блафу и в основном это нулевой указатель ?! Я в полном замешательстве: /

Ответы [ 6 ]

7 голосов
/ 28 октября 2011

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

//............vv
void bla(char **t)

Затем используйте указатель, разыменовав его:

// note the '*' in front of t
*t = (char*) malloc(5);
if (*t != 0) {
    *t[0] = 'h';
    printf("%c\n", *t[0]);
}

Также объявите b как char*, а не какchar b[10].


Почему?Потому что вы пытаетесь изменить указатель.Логика такая же, как и у других типов, но здесь она немного запутана.
Подумайте об этом так: если вам нужно передать int и вам нужно изменить его, вам нужен указатель на int .То же самое и здесь - вам нужно передать указатель на char и вам нужно изменить его, поэтому используйте " указатель на указатель на char ":)


РЕДАКТИРОВАТЬ : в соответствии с вашими правками - да, вы прекрасно это поняли, есть небольшая проблема - приоритет operator* и operator[].Если вы замените *t[X] на (*t)[X], все будет хорошо:)

2 голосов
/ 28 октября 2011

Если вы используете указатель на указатель

void blah(char **t)

Вы можете назначить кусок памяти (в голове), используя malloc как

*t = malloc(size);

и вы бы назвали бла так:

char *b;
bla(&b);

и он будет выделен и заполнен с использованием in blah, и результат может быть напечатан в main.

1 голос
/ 28 октября 2011

Вы передавали указатель на функцию. Через него вы можете навсегда изменить (после возврата функции) только тот объект, на который она указывает, но вы не можете изменить сам указатель, поскольку именно его копия фактически передается в функцию. Все изменения внутри функции производятся на копии указателя. Его первоначальное значение остается неизменным, когда функция возвращается.

(1) Если вы хотите изменить некоторую переменную в какой-либо функции, вам нужно передать на нее указатель. Если эта переменная имеет тип указателя, то передайте на нее указатель - указатель на указатель! В вашем случае эта переменная будет иметь тип char **.

(2) Если вы хотите выделить память в куче в функции, вам не нужно использовать стек - объявите указатель b как char *.

(3) После выделения памяти в куче не забудьте освободить ее, в противном случае вы получите утечки памяти.

(4) Возвращает 0 из вашего приложения, если оно завершается без ошибок. Сохранить другие возвращаемые значения для кодов ошибок - в случае различных ошибок, которые могут возникнуть в вашем приложении, верните разные коды.

И наконец, это приложение на чистом языке Си. В C ++ вы бы использовали new / delete для выделения / освобождения памяти, std :: string вместо char * для строк и std :: cout << вместо printf для отправки текста в выходной поток </p>

void bla(char **pt)               // (1)
{
    *pt = (char*)malloc(5);

    if (*pt != 0) 
    {
        *pt[0] = 'h';
        printf("%c\n", *pt[0]);
    }
}

int main(int argc, char **argv)
{
    char* b = 0;                  // (2)

    bla(&b);
    printf("%c\n", b[0]);

    if(b)
    {
        free(b);                  // (3)
        b = 0;
    }

    return 0;                     // (4)
}
0 голосов
/ 28 октября 2011

Причиной странного поведения во втором примере является приоритет операторов. [] (Скобки, индекс массива) имеет более высокий приоритет, чем * (разыменование)

Итак, *t[1] совпадает с *(t[1]). Вам нужно (*t)[1]

, поскольку t - указатель на указатель на символ:

*(t[1]) означает «взять адрес t, пойти (sizeof (char *)) байтов вперед, разыменовать адрес и снова разыменовать»

(*t)[1] означает «взять адрес t, разыменовать его, идти вперед (sizeof (char)) байтов и снова разыменовать»

На самом деле в первом случае поведение не определено, потому что оно пытается удвоить разыменовывание местоположения после t. В вашем примере первое значение будет всегда печататься, потому что t [0] означает только разыменование, поэтому два случая будут одинаковыми.

0 голосов
/ 28 октября 2011

Если вы хотите вернуть результат, используя ссылку на var, тогда да, вы должны передать указатель на указатель (или просто вернуть результат обычным способом, char * bla ()). Не забывайте нулевые терминаторы!

0 голосов
/ 28 октября 2011

Когда вы пишете char b[10];, у вас есть статически распределенный массив, вам не нужно выделять для него больше места, он подходит для хранения до 10 char значений.

Если вычтобы позволить вашей функции изменять содержимое этого массива, вам просто нужно передать простой указатель, как вы это сделали (но без выделения!):

void bla(char *t)
{
    if (t != 0) {
        t[0] = 'h';
        printf("%c\n", t[0]);
    }
}

После функции значение b у вас main тоже изменилось.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...