Возврат массива с помощью C
Я относительно новичок в C и мне нужна помощь с методами работы с массивами. Исходя из программирования Java, я привык к тому, что могу сказать int [] method()для того, чтобы возвратить массив. Однако я обнаружил, что с C вы должны использовать указатели для массивов, когда вы их возвращаете. Будучи новым программистом, я действительно не понимаю этого вообще, даже со многими форумами, которые я просматривал.
В принципе, я пытаюсь написать метод, который возвращает массив символов в C. Я буду предоставьте метод (давайте назовем его returnArray) с массивом. Он создаст новый массив из предыдущего массива и вернет указатель на него. Мне просто нужна помощь о том, как это начать и как читать указатель, как только он отправляется из массива. Любая помощь, объясняющая это, ценится.
предлагаемый формат кода для функции возврата массива
char *returnArray(char array []){
char returned [10];
//methods to pull values from array, interpret them, and then create new array
return &(returned[0]); //is this correct?
}
вызывающий функцию
int main(){
int i=0;
char array []={1,0,0,0,0,1,1};
char arrayCount=0;
char* returnedArray = returnArray(&arrayCount); ///is this correct?
for (i=0; i<10;i++)
printf(%d, ",", returnedArray[i]); //is this correctly formatted?
}
я не проверял так как мой компилятор C не работает в данный момент, но я хотел бы выяснить это
8 ответов:
вы не можете возвращать массивы из функции в C. Вы также не можете (не должны) делать так:
char *returnArray(char array []){ char returned [10]; //methods to pull values from array, interpret them, and then create new array return &(returned[0]); //is this correct? }
returnedсоздается с автоматическим сроком хранения, и ссылки на него станут недействительными, как только он покинет область объявления, т. е. когда функция вернется.вам нужно будет динамически выделить память внутри функции или заполнить предварительно выделенный буфер, предоставленный вызывающим.
Вариант 1:
динамически выделите память внутри функции (вызывающий объект, ответственный за освобождение
ret)char *foo(int count) { char *ret = malloc(count); if(!ret) return NULL; for(int i = 0; i < count; ++i) ret[i] = i; return ret; }назовем это так:
int main() { char *p = foo(10); if(p) { // do stuff with p free(p); } return 0; }Вариант 2:
заполните предварительно выделенный буфер, предоставленный вызывающим (вызывающий выделяет
bufи переходит к функции)void foo(char *buf, int count) { for(int i = 0; i < count; ++i) buf[i] = i; }и назовем это так:
int main() { char arr[10] = {0}; foo(arr, 10); // No need to deallocate because we allocated // arr with automatic storage duration. // If we had dynamically allocated it // (i.e. malloc or some variant) then we // would need to call free(arr) }
обработка c массивов очень отличается от Java, и вам придется корректировать свое мышление. Массивы в C не являются объектами первого класса (то есть выражение массива не сохраняет его "массивность" в большинстве контекстов). В C, выражение типа " N-элемент массива
T"будет неявно преобразовано ("распад") в выражение типа " указатель наT", за исключением случаев, когда такие выражения операндsizeofили унарный&операторы, или если выражение массива является строковым литералом, используемым для инициализации другого массива в объявлении.кроме всего прочего, это означает, что вы не можете передать выражение массива в функцию и получить его как тип массива; функция фактически получает указатель типа:
void foo(char *a, size_t asize) { // do something with a } int bar(void) { char str[6] = "Hello"; foo(str, sizeof str); }в вызове
foo, выражениеstrпреобразуются из типаchar [6]доchar *, поэтому первый параметрfooобъявленаchar *aвместоchar a[6]. Вsizeof str, так как выражение массива является операндомsizeofоператор, он не преобразуется в тип указателя, поэтому вы получаете количество байтов в массиве (6).если вы действительно интересно, вы можете прочитать Денниса Ричи развитие языка C чтобы понять, откуда берется это лечение.
получается, что функции не могут возвращать массивы, которые нормально так выражения массива также не могут быть целью назначения.
самый безопасный метод для вызывающего объекта-определить массив и передать его адрес и размер функции, которая должна записать в него:
void returnArray(const char *srcArray, size_t srcSize, char *dstArray, char dstSize) { ... dstArray[i] = some_value_derived_from(srcArray[i]); ... } int main(void) { char src[] = "This is a test"; char dst[sizeof src]; ... returnArray(src, sizeof src, dst, sizeof dst); ... }другой метод заключается в том, что функция динамически выделяет массив и возвращает указатель и размер:
char *returnArray(const char *srcArray, size_t srcSize, size_t *dstSize) { char *dstArray = malloc(srcSize); if (dstArray) { *dstSize = srcSize; ... } return dstArray; } int main(void) { char src[] = "This is a test"; char *dst; size_t dstSize; dst = returnArray(src, sizeof src, &dstSize); ... free(dst); ... }в этом случае вызывающий объект отвечает за освобождение массива с помощью
freeфункции библиотеки.отметим, что
dstв приведенном выше коде есть простой указатель наchar, а не указатель на массивchar. Семантика указателя и массива C такова, что вы можете применить оператор индекса[]либо выражение типа Array или тип указателя; какsrc[i]иdst[i]кi' й элемент массива (хотя толькоsrcимеет тип массива).вы можете объявить указатель на N-элемент массива
Tи сделать что-то подобное:char (*returnArray(const char *srcArr, size_t srcSize))[SOME_SIZE] { char (*dstArr)[SOME_SIZE] = malloc(sizeof *dstArr); if (dstArr) { ... (*dstArr)[i] = ...; ... } return dstArr; } int main(void) { char src[] = "This is a test"; char (*dst)[SOME_SIZE]; ... dst = returnArray(src, sizeof src); ... printf("%c", (*dst)[j]); ... }несколько недостатков с выше. Прежде всего, более старые версии C ожидают
SOME_SIZEчтобы быть константа времени компиляции, что означает, что функция будет работать только с одним размером массива. Во-вторых, вы должны разыменовать указатель перед применением индекса, который загромождает код. Указатели на массивы работают лучше, когда вы имеете дело с многомерными массивами.
Как насчет этой восхитительно злой реализации?
массив.h
#define IMPORT_ARRAY(TYPE) \ \ struct TYPE##Array { \ TYPE* contents; \ size_t size; \ }; \ \ struct TYPE##Array new_##TYPE##Array() { \ struct TYPE##Array a; \ a.contents = NULL; \ a.size = 0; \ return a; \ } \ \ void array_add(struct TYPE##Array* o, TYPE value) { \ TYPE* a = malloc((o->size + 1) * sizeof(TYPE)); \ TYPE i; \ for(i = 0; i < o->size; ++i) { \ a[i] = o->contents[i]; \ } \ ++(o->size); \ a[o->size - 1] = value; \ free(o->contents); \ o->contents = a; \ } \ void array_destroy(struct TYPE##Array* o) { \ free(o->contents); \ } \ TYPE* array_begin(struct TYPE##Array* o) { \ return o->contents; \ } \ TYPE* array_end(struct TYPE##Array* o) { \ return o->contents + o->size; \ }главная.c
#include <stdlib.h> #include "array.h" IMPORT_ARRAY(int); struct intArray return_an_array() { struct intArray a; a = new_intArray(); array_add(&a, 1); array_add(&a, 2); array_add(&a, 3); return a; } int main() { struct intArray a; int* it; int* begin; int* end; a = return_an_array(); begin = array_begin(&a); end = array_end(&a); for(it = begin; it != end; ++it) { printf("%d ", *it); } array_destroy(&a); getchar(); return 0; }
в вашем случае вы создаете массив в стеке, и как только вы покинете область действия функции, массив будет освобожден. Вместо этого создайте динамически выделенный массив и верните указатель на него.
char * returnArray(char *arr, int size) { char *new_arr = malloc(sizeof(char) * size); for(int i = 0; i < size; ++i) { new_arr[i] = arr[i]; } return new_arr; } int main() { char arr[7]= {1,0,0,0,0,1,1}; char *new_arr = returnArray(arr, 7); // don't forget to free the memory after you're done with the array free(new_arr); }
Я не говорю, что это лучшее решение или предпочтительное решение данной проблемы. Однако может быть полезно помнить, что функции могут возвращать структуры. Хотя функции не могут возвращать массивы, массивы могут быть обернуты в структуры и функция может возвращать структуру, тем самым неся выбора с ним. Это работает для массивов фиксированной длины.
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char v[10]; } CHAR_ARRAY; CHAR_ARRAY returnArray(CHAR_ARRAY array_in, int size) { CHAR_ARRAY returned; /* . . . methods to pull values from array, interpret them, and then create new array */ for (int i = 0; i < size; i++ ) returned.v[i] = array_in.v[i] + 1; return returned; // Works! } int main(int argc, char * argv[]) { CHAR_ARRAY array = {1,0,0,0,0,1,1}; char arrayCount = 7; CHAR_ARRAY returnedArray = returnArray(array, arrayCount); for (int i = 0; i < arrayCount; i++) printf("%d, ", returnedArray.v[i]); //is this correctly formatted? getchar(); return 0; }Я предлагаю прокомментировать сильные и слабые стороны этой техники. Я не потрудился сделать это.
Вы можете сделать это с помощью динамической памяти (через malloc () ссылка), как и другие ответы, представленные здесь, но вы всегда должны управлять памятью (использовать free ()
ваш метод вернет локальную переменную стека, которая будет плохо работать. Чтобы вернуть массив, создайте его вне функции, передайте его по адресу в функцию, затем измените его или создайте массив в куче и верните эту переменную. Оба будут работать, но первый не требует никакого динамического выделения памяти, чтобы заставить его работать правильно.
void returnArray(int size, char *retArray) { // work directly with retArray or memcpy into it from elsewhere like // memcpy(retArray, localArray, size); } #define ARRAY_SIZE 20 int main(void) { char foo[ARRAY_SIZE]; returnArray(ARRAY_SIZE, foo); }
вы можете использовать такой код:
char *MyFunction(some arguments...) { char *pointer = malloc(size for the new array); if (!pointer) An error occurred, abort or do something about the error. return pointer; // Return address of memory to the caller. }когда вы это сделаете, память позже должна быть освобождена, передав адрес в free.
есть и другие варианты. Процедура может возвращать указатель на массив (или часть массива), который является частью некоторой существующей структуры. Вызывающий объект может передать массив, и процедура просто записывает в массив, а не выделяет пространство для нового массива.
Comments