C возврат массива в функцию


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

int a [];
int* a;
int *a;

В java я бы сделал что-то вроде этого, чтобы вернуть массив в функцию:

int [] returnArr(int [] a){
... modify a ...
return a;
}

int [] a = {...};
int [] b = returnArr(a); ##

Как я могу сделать то же самое в C, особенно части с ##.

Отредактировано: У меня есть такая функция:

float *normalizeValues(float *v, float maxY){

    int size = sizeof(v) / sizeof(float);
    float max = findMax(v);
    float ratio = maxY / max;
    int i;
    for(i = 0; i < size ; ++i){
        v[i] = v[i] * ratio;
    }
    return v;
}

И я делаю следующее:

float vert [] = {306, 319, 360, 357, 375, 374, 387, 391, 391, 70, 82, 94, 91, 108, 114, 125, 127, 131};
int i = 0;
float *vert2;
vert2 = normalizeValues(vert, 0.7);

for(i = 0; i < sizeof(vert2) / sizeof(float); ++i){
    fprintf(stdout,": %fn",vert2[i]);
}

И выход только 1 элемент.

5 2

5 ответов:

EDIT: чтобы напрямую ответить на ваш обновленный вопрос, вы должны передать размер массива. C не имеет механизма для хранения размера массивов, как это делает Java. Если компилятор знает о размере массива, так как массив является глобальной или локальной переменной, не выделяемой динамически, то можно использовать оператор sizeof (). В противном случае вы должны знать размер отдельно или использовать значения sentinel в вашем массиве (например, 0.0 в конце или NULL).

Что касается массивов, указателей и аргументы в целом см. ниже:

Вы будете возвращать указатель на массив, который обозначается синтаксисом'*':

int *returnArr(int[] a) {
    // modify a...
    return a;
}

int a[] = { ... };
int *b;
b = returnArr(a);

Несколько вещей, чтобы отметить:

  • вы не можете выполнять назначения в объявлениях переменных, которые включают непостоянные выражения (например, вызовы функций). Однако в С99 ситуация могла измениться.
  • Скобки идутпосле имени переменной, в отличие от Java, где они являются частью типа. Несмотря на то, что синтаксис Java больше непротиворечиво, это не совсем имеет смысл в C, где вы часто даете размер массива в скобках в объявлении переменной:

    int a[3] = { ... };

  • Невозможно указать, что функция возвращает массив, а не простой указатель. В C ссылки на массивы распадаются на указатели (хотя указатели и массивы-это не одно и то же, как обычно утверждают). Это означает, что всякий раз, когда вы передаете массив, C предоставляет только средство для передачи указателя на массив. Весь массив на самом деле не копируется. Как это происходит, имя массива также является указателем на первый элемент массива.

Пожалуйста, также обратите внимание на то, что user268396 говорит в своем ответе. Если вы планируете создать новый массив и вернуть его, вам нужно будет либо выделить массив динамически, либо передать указатель на уже выделенный массив (что, похоже, вы все равно делаете).

Вы не можете. когда функция возвращает кадр стека будет стерт (как правило), и ваш сгенерированный массив будет разбит этим. Однако вы можете изменить прототип функции, чтобы принять указатель на массив для изменения. Этот вид аргумента функции известен как"выходной параметр". Пример:

void function func(int a, int b, int[2] to_modify)
{
  to_modify[0] = a;
  to_modify[1] = b;
}
int main()
{
   int foo[2];
   func(1, 2, foo);
   printf("Result: foo[0] = %d, foo[1] = %d\n", foo[0], foo[1]);
   return 0; 
}

Это выведет "результат: foo[0] = 1, foo[1] = 2".

Надеюсь, это поможет

  #include<stdio.h>

    void change(int *c)/*Pointer c now has the first location of the array a[]*/
    {
      *(c+0) = 0;/*assign values to the array by adding step-size to the first array position*/
      *(c+1) = 1;
      *(c+2) = 2;
      *(c+3) = 3;
      *(c+4) = 4;
    }

    main()
    {
      int a[5]={10,20,30,40,50}; /* Declare and Assign an array a[] of size 5.*/
      int *b = a; /*Declare and assign a Pointer to the location of the array.*/
      change(b); /*pass the pointer(which is now pointing to first position of array) to the change() function.*/
      printf("%d,%d,%d,%d,%d,",a[0],a[1],a[2],a[3],a[4]);/*Print the changed value.*/
    }

Выход: 0,1,2,3,4,

С точки зрения Java указатели просто похожи (не совсем) на ссылки на объекты.

Object O;

O = New SomeClassName();

Как ссылка на объект O указывает на некоторый фактический объект типа SomeClassName, так и указатели в C:

int *b;
b = &a;

Переменная b является просто указывает на адрес. Глубокое погружение в концепции массива:

int a[5];
int *b = a;

Здесь мы просто говорим, что Mr*b указывает на первое местоположение группы a то есть a[0] .

Теперь указатель мощности в C - это то, что отныне, здесь после:

*b means a[0]
*(b+1) means a[1]
*(b+2) means a[2]
*(b+3) means a[3]
*(b+4) means a[4]
Это означает, что вы меняетесь в *(b+4), вы меняете a[4].
int* returnArr(int a[]){
    //modify a
    return a;
}
Следует отметить, что при использовании массива в списке параметров функции он будет преобразован в указатель. Так что в основном(...) декларации, char *argv[] и char **argv фактически одинаковы. В этом случае int a[] и int* a-одно и то же. Но массив и указатель-это не одно и то же.

Возьмем в качестве примера следующий код:

int a[10];
int main(){
    int *p = a;
    p[5] = 4;
    return p[5];
}

P-указатель, когда мы обращаемся к p[i], обратите внимание, что адрес p не является адресом a, содержимое p является адресом a. тогда код воля:

  1. доступ к памяти, чтобы получить содержимое p, то есть адрес a.
  2. вычислите смещение на основе i и типа указателя (int).
  3. доступ к памяти, чтобы получить результат.

A-массив int, если мы обращаемся к a[i], адрес a-это просто адрес a[0], код будет:

  1. вычислите смещение на основе i и типа int.
  2. доступ к памяти.

Указатель и массив-это разные типы. Так что если вы объявите int *p в одном файле и используйте его в этом файле, но определите p как массив в другом файле, что вызовет проблему.

Вы также можете задаться вопросом о int *p = a, в ANSI, если вы используете массив(его имя) в качестве выражения, компилятор преобразует его в указатель, указывающий на самый первый элемент массива.

Обновление на основе комментариев Джима Балтера:

Если вы используете массив(его имя) в качестве выражения, компилятор не всегда преобразует его в указатель, указывающий на самый первый элемент массива. Например, в sizeof (p - >q - >a) P->q - >a является выражением, но если a-массив, то он не преобразуется в указатель.

" за исключением случаев, когда это операнд оператора sizeof или унарный & оператор, или строковый литерал, используемый для инициализации массива, является выражение, имеющее тип "массив типа", преобразуется в выражение с типом ‘указатель на тип’, указывающее на начальное значение элемент массива объект.

В языке C можно возвращать только указатель массива в функции. Например, если вы хотите вернуть строку(массив символов) в функции, вы можете вернуть указатель на строку с нулевым окончанием. Если вы хотите вернуть массив какого-то другого типа(int, user-defined struct и т. д.), Вы можете выделить некоторую память для хранения массива и вернуть указатель на массив, вернуть размер массива в параметре. Пример:

int *function(int *size)
{
    *size = 10;
    int *intP = (int *)malloc((*size)*sizeof(int));

    return intP;
}