Используйте модуль. Он импортируется только один раз. Определите в нем глобальные переменные - они будут атрибутами singleton. Добавьте некоторые функции - методы «singleton».
Вы не можете возвращать массивы из функций из 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)
}
Вы можете использовать такой код:
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.
}
Когда вы это сделаете, память должна быть освобождена позже, передав адрес бесплатно.
Есть другие варианты , Подпрограмма может возвращать указатель на массив (или часть массива), который является частью некоторой существующей структуры. Вызывающий может передать массив, и программа просто записывает в массив, а не выделяет пространство для нового массива.
Я не говорю, что это лучшее решение или предпочтительное решение данной проблемы. Однако может быть полезно помнить, что функции могут возвращать структуры. Хотя функции не могут возвращать массивы, массивы могут быть обернуты в структуры, и функция может возвращать структуру, тем самым перенося массив с ней. Это работает для массивов с фиксированной длиной.
#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;
}
Я предлагаю комментарии о сильных и слабых сторонах этого метода. Я не удосужился это сделать.
Обработка 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).
Если вы заинтересованы в действительно , вы можете прочитать Dennis Ritchie's «Развитие языка 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-указатель и семантика массива таковы, что вы можете применить индексный оператор []
к выражению типа указателя типа или ; оба 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
будет константой времени компиляции, что означает, что функция будет работать только с одним размером массива. Во-вторых, вы должны разыменовать указатель перед применением индекса, который загромождает код. Указатели на массивы работают лучше, когда вы имеете дело с многомерными массивами.
bar
получает, является указателем, а не массивом. В контексте объявления параметра функции T a[N]
и T a[]
рассматриваются как T *a
.
– John Bode
14 April 2016 в 12:16
В вашем случае вы создаете массив в стеке, и как только вы покинете область действия, массив будет освобожден. Вместо этого создайте динамически выделенный массив и верните указатель на него.
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);
}
sizeof(char)
гарантированно 1
, поэтому в этом случае вы можете отбросить этот бит с malloc
.
– Ed S.
25 July 2012 в 19:54
&arr
. Вы хотите arr
быть char *
и передать его с помощью arr
.
– chris
25 July 2012 в 19:56
Вы можете сделать это с помощью памяти кучи (через вызов malloc () ), как и другие ответы, описанные здесь, но вы всегда должны управлять памятью (используйте функцию free () каждый раз, когда вы вызываете свою функцию). Вы также можете сделать это со статическим массивом:
char* returnArrayPointer()
{
static char array[SIZE];
// do something in your array here
return array;
}
Вы можете использовать его, не беспокоясь об управлении памятью.
int main()
{
char* myArray = returnArrayPointer();
/* use your array here */
/* don't worry to free memory here */
}
В этом примере вы должны использовать статическое ключевое слово в определение массива, чтобы установить продолжительность жизни массива в приложении, поэтому он не будет уничтожен после оператора return. Разумеется, таким образом вы занимаете байты SIZE в своей памяти на весь срок службы приложения, поэтому его размер будет правильным!
Ваш метод вернет переменную локального стека, которая будет терпеть неудачу. Чтобы вернуть массив, создайте его вне функции, передайте его по адресу в функцию, затем измените его или создайте массив в куче и верните эту переменную. Оба будут работать, но первый не требует никакого динамического распределения памяти, чтобы заставить его работать правильно.
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);
}
Как насчет этой невероятно злой реализации?
array.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; \
}
main.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;
}
struct
как контейнер / объект массива. Подумайте об этом, как C ++ std :: vector. Препроцессор расширил версию int
до struct intArray { int* contents; int size; };
.
– pyrospade
9 January 2014 в 06:05