Возвращение массивов с C, разные подходы - PullRequest
0 голосов
/ 24 апреля 2011

Ранее я задавал этот вопрос: Экспериментируя с указателями массивов в C относительно передачи указателей на функции и модификации существующих массивов внутри функций в качестве способа "возврата" массива в main().У меня остается вопрос, в чем разница между этими двумя блоками кода?

// #includes

int ***myfunc(int*** );

int main() 
{
    int a***;
    //allocate memory for array 'a'
    a = myfunc(a);

    // display all contents of array 'a'

    return 0;
}

ИЛИ

// #includes

void myfunc(int*** );

int main() 
{
    int a***;
    //allocate memory for array 'a'
    myfunc(a);

    // display all contents of array 'a'

    return 0;
}

Обе функции изменят массив, и когда displaying all contents of a,содержимое будет таким же.

Надеюсь, это не сбивает с толку, думаю, я мог бы уточнить больше, если это необходимо.

значительное EDITTTTTTTTT

Ниже приведены два рабочих примера (насколько я знаю):

#include "stdlib.h"
#include "stdio.h"


void myfunc(int** );

int main() {

  int **a,i, j;

  a = (int**) calloc(10,sizeof(int*));
  for (i=0; i<10; i++)
    a[i] = (int*) calloc(10, sizeof(int));

  myfunc(a);

  for (i=0; i<10; i++) {
    for (j=0; j<10; j++)
      printf("%d ",a[i][j]);
    printf("\n");
  }

  return 0;
}


void myfunc(int** a) {

  int i, j;
  for (i=0; i<10; i++)
    for (j=0; j<10; j++)
      a[i][j] = i*j;

}

И ...

#include "stdlib.h"
#include "stdio.h"

// returning arrays through functions

int **myfunc(int **b);

int main() {

  int **a,i,j;

  a = (int**) calloc(10,sizeof(int*));
  for (i=0; i<10; i++)
    a[i] = (int*) calloc(10, sizeof(int));

  a = myfunc(a);

  for (i=0; i<10; i++) {
    for (j=0; j<10; j++)
      printf("%d ",a[i][j]);
    printf("\n");
  }

  return 0;
}


int **myfunc(int **b) {

  int i, j;
  for (i=0; i<10; i++)
    for (j=0; j<10; j++)
      b[i][j] = i*j;

  return b;
}

Ответы [ 2 ]

3 голосов
/ 24 апреля 2011

Вторая функция не может изменить указатель (int***), который вы передаете в него, но когда вы сделаете выделение, вы получите новый адрес памяти.Этот новый адрес будет назначен локальной копии указателя внутри myfunc, но он никогда не достигнет main.

Следствием этого является то, что вы будете:

  • Используйте недопустимый указатель внутри main
  • Утечка памяти, выделенной внутри myfunc.

Вы можете уменьшить это, взяв указатель науказатель (вот так!):

// #includes

void myfunc(int****);

int main() 
{
    int ***a; // <-- note: you had a typo here, originally!

    //allocate memory for array 'a'
    myfunc(&a); // <-- pass pointer by pointer

    // display all contents of array 'a'

    return 0;
}

и убедитесь, что myfunc умен в этом.

Приведенный выше код можно сделать более понятным с помощью typedef:

// #includes
typedef int*** Ptr;

void myfunc(Ptr*);

int main() 
{
    Ptr a;

    //allocate memory for array 'a'
    myfunc(&a); // <-- pass pointer by pointer

    // display all contents of array 'a'

    return 0;
}

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


Редактировать (ответ на важный вопрос редактирования)

Я понял, что выделение памяти было сделано в myfunc;Теперь я вижу, что это не так.

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

0 голосов
/ 24 апреля 2011

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

myfunc(&a); // as opposed to myfunc(a);

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

int **myfunc(int ***a) { ... }

, поэтому вызов в main будет выглядеть примерно так:

int **a, **b;

b = myfunc(&a);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...