[c] C를 사용하여 배열 반환

나는 C를 처음 접했고 배열을 다루는 메소드에 대한 도움이 필요하다. Java 프로그래밍에서 왔으므로 int [] method()배열을 반환하기 위해 말할 수있었습니다 . 그러나 C를 사용하면 배열을 반환 할 때 포인터를 사용해야한다는 것을 알았습니다. 새로운 프로그래머이기 때문에, 내가 살펴본 많은 포럼 에서조차도 이것을 전혀 이해하지 못합니다.

기본적으로 C에서 char 배열을 반환하는 메서드를 작성하려고합니다. 배열과 함께 메서드를 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 컴파일러가 현재 작동하지 않기 때문에 아직 테스트하지 않았지만 이것을 파악하고 싶습니다.



답변

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-element array of 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 *되므로의 첫 번째 매개 변수 foochar *a대신 선언 됩니다 char a[6]. 에서 sizeof str배열 표현식의 피연산자이기 때문에, sizeof작업자가 어레이 (6)의 바이트 수를 얻을 수 있도록, 그것은, 포인터 형식으로 변환 아니에요.

정말로 관심 이 있다면 Dennis Ritchie의 The 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는 컴파일 타임 상수가 될 것으로 기대 합니다. 즉, 함수는 하나의 배열 크기에서만 작동합니다. 둘째, 아래 첨자를 적용하기 전에 포인터를 역 참조하면 코드가 복잡해집니다. 다차원 배열을 다룰 때 배열에 대한 포인터가 더 잘 작동합니다.


답변

나는 이것이 주어진 문제에 대한 최선의 해결책이거나 선호되는 해결책이라고 말하지 않습니다. 그러나 함수가 구조체를 반환 할 수 있다는 것을 기억하는 것이 유용 할 수 있습니다. 함수는 배열을 반환 할 수 없지만 배열은 구조체로 래핑 될 수 있으며 함수는 구조체를 반환하여 배열을 전달할 수 있습니다. 고정 길이 배열에서 작동합니다.

    #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;
    }

이 기술의 강점과 약점에 대한 의견을 제시합니다. 나는 그렇게 귀찮게하지 않았습니다.


답변

이 맛있게 나쁜 구현은 어떻습니까?

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;
}


답변

귀하의 경우 스택에 배열을 작성하고 함수 범위를 벗어나면 배열이 할당 해제됩니다. 대신 동적으로 할당 된 배열을 만들고 그에 대한 포인터를 반환하십시오.

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);

}


답변

여기에보고 된 다른 답변과 같이 힙 메모리 ( 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 */
}

이 예제에서는 배열 정의에 static 키워드를 사용하여 배열 수명 기간 동안 응용 프로그램으로 설정해야하므로 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);
}