Понимание типа возвращаемых данных C - PullRequest
0 голосов
/ 24 марта 2020

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

long long (* convertFra c) [2]

? И почему мой тип возвращаемых данных не подходит? Может кто-нибудь объяснить мне или дать подсказку, как правильно гуглить такой вопрос? Я думал, что выделение памяти и возврат указателя было бы хорошо, но это не так.

long long (*convertFrac(long long lst[][2], int row))[2] {
  long long **out = malloc(row*sizeof(long long*));
  long long * result = (long long *)malloc(row*2*sizeof(long long));
  for (size_t i = 0; i < row; i++)
  {
    out[i] = result+i*2;
  }
  ...
  return out;
}

пример:

long long (*data)[2] = convertFrac((long long [][2]){ {1, 2}, {1, 3}, {1, 4} }, 3); // data should be {{6, 12}, {4, 12}, {3, 12}}

Ответы [ 3 ]

1 голос
/ 24 марта 2020

long long (*convertFrac)[2] - указатель. Указатель на массив 2 из long long.

Полезный сайт: C gibberi sh ↔ Engli sh


Returning long long **out не совместимо с возвратом long long (*)[2]. Просто верните long long (*)[2].

Похоже, что OP хочет распределять и назначать вычисления с использованием заданного составного литерала . Для этого

#define COL_N 2

long long (*convertFrac(long long lst[][COL_N], int row))[COL_N] {
  // Corrected and simplified allocation
  long long (*data)[COL_N] = malloc(sizeof *data * (size_t) row);
  if (data == NULL) {
    return NULL;
  }

  // At this point, there is some calculation of the LCD based on lst.
  // I'll leave that calculation to OP as the question is about return types.
  long long lcm = lcm(lst, row);

  for (int r = 0; r < row; r++) {
    long long multiplier = lcm/lst[r][COL_N-1];
    for (int c = 0; c < COL_N; c++) {
      data[r][c] = multiplier*lst[r][c];
    }
  }
  return data;
}
0 голосов
/ 24 марта 2020

иногда хорошо использовать typedef, чтобы сделать его более читабельным для человека

typedef long long lla2[2];

lla2 *foo()
{
    long long (*data)[2] = malloc(sizeof(*data));

    return data;
}

lla2 *bar()
{
    lla2 *data = malloc(sizeof(*data));

    return data;
}

lla2 *noo(lla2 *ptr)
{
    return ptr + 1;
}

А ваша сигнатура функции будет

lla2 *convertFrac(lla2 *lst, int row)

Тело функции не имеет никакого смысла, поэтому Трудно сказать, что вы хотите архивировать

0 голосов
/ 24 марта 2020

Массивы не совпадают с указателями. Тип long long (*)[2] является указателем на массив из 2 long long с. Тип long long ** является указателем на указатель на long long. Два типа несовместимы.

Чтобы объявить что-то типа long long (*)[2], что-то идет между * и ). Например, простая переменная foo типа long long (*)[2] будет объявлена ​​как long long (*foo)[2];. Для функции, возвращающей long long (*)[2], это имя функции и список ее параметров находятся между * и ). Например, функция bar, принимающая один параметр int a и возвращающая long long (*)[2], будет объявлена ​​как long long (*bar(int a))[2];.

. Из вопроса следует, что функция convertFrac должна скопируйте массив дробей (каждая дробь представлена ​​long long [2]) и преобразуйте их, чтобы использовать общий знаменатель. Следующий код выполняет большую часть этого, кроме вычисления общего знаменателя:

long long lcm(long long a, long long b); // to be written

long long (*convertFrac(long long lst[][2], int row))[2] {
  long long (*result)[2] = malloc(row*sizeof(*result));
  long long d;
  int i;

  // determine common denominator
  d = 1;
  for (i = 0; i < row; i++) {
    d = lcm(d, lst[i][1];
  }

  // convert fractions to common denominator
  for (i = 0; i < row; i++) {
    result[i][0] = lst[i][0] * (d / lst[i][1]);
    result[i][1] = d;
  }

  return result;
}

Подходящий typedef для типа дроби сделает код более читабельным:

typedef long long fraction[2];

fraction *convertFrac(fraction lst[], int row) {
  fraction *result = malloc(row*sizeof(*result));
  ...
  return result;
}
...