2014-02-20 3 views
3

Следуя советам C FAQ on instantiating a matrix using a double pointer, я наткнулся на другую проблему. Мне удалось решить проблему, но мне трудно понять, почему она работает в одном направлении, но не в другом.Изменение переменной, переданной по ссылке, и возврат ее из функции

У меня есть следующий код, который работает, а затем я покажу вам немного, что не работает, и я надеюсь, что вы можете объяснить, почему:

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

int HEIGHT = 20; 
int WIDTH = 20; 

int ** curr_grid; 

/** 
* Generate an array with the given height and length 
*/ 
int ** create_grid() { 
    int ** grid; 
    grid = malloc(sizeof(int *) * HEIGHT); 
    int row; 
    for (row = 0; row < HEIGHT; row++) 
     grid[row] = malloc(sizeof(int) * WIDTH); 
    return grid; 
} 

/* Entry Point main */ 
int main(int argc, char** argv) { 
    curr_grid = create_grid(); 
    curr_grid[0][0] = 0; 
    free(curr_grid); // Release heap resources 
    return 0; 
} 

Выделяя память для сетки и возвращая указатель таким образом работает. Тем не менее, я впервые попробовал еще один способ, который я был убежден, должен также работать, но это не делает:

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

int HEIGHT = 20; 
int WIDTH = 20; 

int ** curr_grid; 

/** 
* Generate an array with the given height and length 
*/ 
create_grid(int ** grid) { 
    grid = malloc(sizeof(int *) * HEIGHT); 
    int row; 
    for (row = 0; row < HEIGHT; row++) 
     grid[row] = malloc(sizeof(int) * WIDTH); 
} 

/* Entry Point main */ 
int main(int argc, char** argv) { 
    create_grid(curr_grid); 
    curr_grid[0][0] = 0; // Segmentation Fault 
    free(curr_grid); // Release heap resources 
    return 0; 
} 

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

Почему это не сработало?

+0

«сетка» внутри функции - это ** копия ** параметра, который передается из 'main' ... –

+1

ваш заголовок говорит« передано по ссылке », но вы на самом деле этого не делаете. –

+0

Это, вероятно, означает, что я полный новичок C. Если у вас есть идеи по переименованию вопроса, я был бы очень благодарен. – mydoghasworms

ответ

1

Вы хотите:

void create_grid(int ***grid) { 
    *grid = malloc(sizeof(int *) * HEIGHT); 
    int row; 
    for (row = 0; row < HEIGHT; row++) 
     (*grid)[row] = malloc(sizeof(int) * WIDTH); 
} 

/* Entry Point main */ 
int main(int argc, char** argv) { 
    create_grid(&curr_grid); 
    curr_grid[0][0] = 0; 
    free(curr_grid); // Release heap resources 
    return 0; 
} 

Это как на примере ниже:

int MyFunction() 
{ 
    return 3 ; // we return directly 3 
} 

void main() 
{ 
    int a ; 
    a = MyFunction() ;  
} 

против:

void MyFunction1(int *pa) 
{ 
    *pa = 3 ; // we assign 3 to the memory location pointed by pa 
} 

void main2() 
{ 
    int a ; 
    MyFunction1(&a) ; // we pass the pointer to a/
    // now a contains 3 
} 
+0

Значит, вы говорите, что я должен передать указатель на указатель? Я думал в силу факта – mydoghasworms

+0

Да. Если вы хотите изменить int через функцию void (например, выше), вы должны передать указатель на 'int'. Если вы хотите изменить указатель на int вы должны передать указатель на указатель на 'int' и т. д. В вашем случае вы хотите изменить указатель на указатель на int (' int ** currgrid'), и поэтому вы должны передать указатель на указатель на указатель.Пожалуйста, примите мой ответ, если он хочет, чтобы вы искали. –

+0

Я не уверен, согласен ли ваш ответ или const. Он дал лучшее объяснение, но не полностью демонстрирует его в коде с помощью * ** подобный сделав. – mydoghasworms

2

Вы не передавая адрес указателя, говоря create_grid(curr_grid); здесь его передача значения, присутствующего в указателе curr_grid (случайное значение) и ваше значение в сетке. который берется из стека, как только выполнение функции завершено.

Попробуйте передать адрес указателя, который затем будет работать нормально.

create_grid(&curr_grid);

EDIT: Проверьте ссылку надеюсь, что это может помочь вам с графическим представлением

Pointer tutorial

+0

Мне жаль, что не было графического объяснения того, что происходит в памяти, когда это происходит, чтобы объяснить, что не так с моим пониманием указателей. Спасибо, на данный момент я должен принять ваше слово, пока он не проникнет в мой толстый череп :-) – mydoghasworms

+0

Я не уверен, принять ли ваш ответ или Майкла. Он лучше продемонстрировал код с функцией ***, но вы дали лучшее объяснение. – mydoghasworms

0

Путь знать, как передать какой-либо переменной (указатель или нет, правила остается неизменным) заключается в следующем:

void create_grid(int **grid) { 
    grid = malloc(...); 
    ... 
} 

Здесь вы передаете переменную с именем grid, и вы хотите изменить его значение grid = malloc(...);, но поскольку вы используете только grid без каких-либо *, у вас есть только копия сетки , и любые внесенные изменения в grids значение не будет видно за пределами функции.

Теперь в этом случае:

void create_grid(int ***grid) { 
    *grid = malloc(...); 
    ... 
} 

Теперь, когда вы обращаетесь к стоимости сетки с использованием и «*», вы знаете, что любые изменения, сделанные таким образом, будут оставаться после возвращения функции, так как сетка действительно ссылка на ваш двумерный массив.

Это просто (независимо от типа переменной).

Смежные вопросы