2013-01-12 13 views
11

以下のように配列名を返そうとしました。基本的には、関数テストがmainで使用できる配列を返すようにしようとしています。このような機能をどのように実行するかを知るために私がもっと知る必要があるものについて私に助言してもらえますか?C関数から配列戻り値型を作る方法は?

#include <stdio.h> 

int test(int size, int x){ 
    int factorFunction[size];  
    factorFunction[0] = 5 + x; 
    factorFunction[1] = 7 + x; 
    factorFunction[2] = 9 + x; 
    return factorFunction; 
} 

int main(void){ 
    int factors[2]; 
    factors = test(2, 3); 
    printf("%d", factors[1]); 
    return 0; 
} 

私は、コンパイラのエラーを受け取る:

smallestMultiple.c:8: warning: return makes integer from pointer without a cast 
smallestMultiple.c:8: warning: function returns address of local variable 
smallestMultiple.c: In function ‘main’: 
smallestMultiple.c:13: error: incompatible types in assignment 
+0

既に多くの素晴らしい回答があります。私からのちょっとしたメモ: 'factorFunction'は"あなたの配列の最初の(または0番目の)要素のアドレス "を指しています。 '&factorFunction [0]'と同じ意味で、 "0番目の要素のアドレス"に変換されます。 – wpp

+0

こんにちはコメントのおかげで!私はこれを理解していますが、実際に1を1にすることを意図しました.0番目のインデックスを無視するのは悪い習慣と考えられますか? – user1530249

+0

あなたは0番目の要素を無視してはいけません!これまで慣れてきたことがありますが、それは必須です(ルビーのような高級言語の場合でも)。 – wpp

答えて

15

機能は、しかしC.

で配列を返すことができない、彼らは構造体を返すことができます。構造体に配列を含めることができます...

+0

Cで配列を返すには、ポインタ戻り型関数を使用します。 –

+0

@MohdShibli - それは全く同じではありませんが、タイプワイズです。そして、ローカル配列へのポインタを返すとUBとなるので、回避策が必要です。 –

+0

ローカル配列の問題は、ローカル配列を静的にすることで簡単に解決できます。 –

8

ヒープにメモリを割り当ててポインタを返す必要があります。 Cは関数から配列を返すことはできません。

int* test(int size, int x) 
{ 
    int* factorFunction = malloc(sizeof(int) * size);  
    factorFunction[0] = 5 + x; 
    factorFunction[1] = 7 + x; 
    factorFunction[2] = 9 + x; 
    return factorFunction; 
} 
+0

これは同じではありません。配列は、スペースの局所性を保証するスタック上の連続したメモリブロックです。 mallocはスペースの局所性を保証するだけでなく(あるmallocが他のmallocから遠いかもしれない)、十分なメモリがない場合にも失敗する可能性があります。したがって、この特定の質問に対する答えではなく、関数から複数形を返す別の方法ですが、それは疑問ではありません。 – Dmitry

3

エラーメッセージの最初の行は、それが言う正確に何を意味:あなたはintを返すとしての機能を宣言しましたが、まだあなたは、ポインタを返すようにしてみてください。
エラーメッセージの2行目に示すように、ポインタを返そうとしている配列がローカル配列であるため、関数が返ってもはやスコープから外れることになります有効です。
あなたがしなければならないことは、mallocまたはnewを使用して配列(すなわち、連続したメモリのチャンク)を動的に割り当てて、そのポインタを返します。もちろん、それを済ませたらメモリを解放してください。

12

ポインタを返すことで配列を返すことができます(配列はポインタから消滅します)。しかし、それはあなたの場合には悪いでしょう。そうすれば、ローカル変数へのポインタを返すことになり、その結果、未定義の動作になります。これは、スタック空間が他の関数によって再利用されるため、関数が返った後に返されたポインタが指すメモリが有効でなくなったためです。

あなたがすべきことは、配列とそのサイズを両方とも関数の引数として渡すことです。

コードに別の問題があります。サイズ2の配列を使用していますが、の3番目の要素に書き込んでください。あなたはまた、私はまず

+0

良い説明、男。ありがとう! – felipsmartins

0
#include <stdio.h> 

#include <stdlib.h> 

int* test(int size, int x){ 
    int *factorFunction = (int *) malloc(sizeof(int) * size);  
    if(factorFunction != NULL) //makes sure malloc was successful 
    { 
     factorFunction[0] = 5 + x; 
     factorFunction[1] = 7 + x; 
     factorFunction[2] = 9 + x; //this line won't work because your array is only 2 ints long 

    } 
return factorFunction; 
} 

int main(void){ 
    int *factors; 
    factors = test(2, 3); 
    printf("%d", factors[1]); 
    //just remember to free the variable back to the heap when you're done 
    free(factors); 
    return 0; 
} 

必要がありますあなたは下の文を使用することはできませんCで一定である:

第二
int factorFunction[size]; 

、あなたはスコープの外に削除される関数で作成された配列を返すようにしようとしています。

これを避けるには、配列をテスト関数のパラメータとして使用するか、malloc関数を使用して動的に配列を作成します。 Btw test関数は、更新された配列へのポインタを返すことができます。私の提案は、埋めるために配列を渡すことであろう

0

上で述べてきたように、あなたがVLA秒を持っているC99を持っていない限り、あなたが実際に設定されているインデックスは、あなたの配列で、配列のサイズを存在していることを確認したい場合があります

+0

彼はどのスタンダードを使用しているのかよくわかりませんが、C99にはVLAがあります。 – Jack

+0

'int factorFunction [size]'に何が問題なのですか? – wpp

+0

@sytycsジャックが正しいです。私たちは彼が何を使用しているのか分からない。私はANSI Cを使っていると思っていました。なぜなら、私たちは学校でANSI Cのスタンドを書くことが期待されていたからです。 Jackは、C99スタンドアットで[可変長配列](http://en.wikipedia.org/wiki/Variable-length_array)を追加しました。 –

0

:この方法で

void test(int size, int factors[], int x){ 
    factorFunction[0] = 5 + x; 
    factorFunction[1] = 7 + x; 
    factorFunction[2] = 9 + x; 
} 

int main(void){ 
    int factors[3]; 
    test(3, factors, 3); 
    printf("%d", factors[1]); 
    return 0; 
} 

、あなたは割り当てを心配する必要はありません、と後で上のアレイを解放する必要はありません。 。

また、配列のサイズを修正しました。そのため、3番目の要素で外側に書き込まないようにしました。 C配列は "どれくらいの数"で宣言されてから0 ... (how_many-1)にインデックスされるので、[2]で宣言された配列の[2]は配列の外に出ます。

-2

メインfunction..Hopeにユーザー定義関数から戻って 配列を返す方法を非常に非常に基本的なコードと非常に非常に基本的な説明は 役立ちます!以下は、私が完全なコードを与えて、理解できるようにしたところです。 正確にどのように動作するのですか? :) :)ここ

#include<iostream> 
using namespace std; 

int * function_Random()// function with returning pointer type of integer 
{ 
    static int arr[100]; 
    cout<<"We are Inside FunctionRandom"<<endl; 
    for(int i=0;i<100;i++)//loop to add elements in array 
    { 
     arr[i]=rand();//rand() function to put random numbers generated by system 
     cout<<"\t"<<arr[i]; //to show how our array will look 
    } 
    cout<<endl<<endl;//endl for end line to look well formatted 
    return arr; 
} 
int main() 
{ 


    int *arrptr; //pointer to get back base address of array 
    arrptr=function_Random();//function that returns base address 
    cout<<"We are Inside Main"<<endl; 
    for(int j=0;j<100;j++) 
    { 
     cout<<"\t"<<arrptr[j];//returned base address has complete link of array that's why it is able to print the array:contiguous memory locations. 
    }  
    return 0;//nothing to return that's why 0 
} 
+1

こんにちは!このコードは、関数ローカル配列( 'return arr;')のアドレスを返し、未定義の動作をします。他のコピー/貼り付け済みの重複のいずれかを削除しましたが、この同じ誤ったコードで2つの回答があります。 – Blastfurnace

+0

@Blastfurnaceどこで修正すればよいですか? – Ruchir

+0

配列 'int arr [100];の有効期間は、定義されている関数の本体に限られます。あなたが 'return arr;'を返すと、呼び出し元に、他の自動変数で上書きできるメモリへのポインタが渡されます。 1つの解決策は、 'malloc'を使って関数内にメモリを割り当て、そのポインタを返すことです。もちろん、呼び出し側はメモリを解放するために 'free'を呼び出す責任があります。あるいは、呼び出し元は配列に関数を渡してデータを埋め込むことができます。 – Blastfurnace

0

アレイをバック渡す別の方法である:

int test(){ 
     static int factorFunction[3];  
     factorFunction[0] = 5 + x; 
     factorFunction[1] = 7 + x; 
     factorFunction[2] = 9 + x; 
     return factorFunction; 
    } 

静的変数は、それがメモリに残ることのようにして割り当てられることを示しています。したがって、値の固定サイズがあり、関数呼び出しの間にメモリ内に残したい場合は、これを行う方法の1つです。

1

残念なことに、Cは関数から任意の配列や匿名の構造体を返すことをサポートしていませんが、2つの回避策があります。

最初の回避策は、配列を含む構造体を作成することです。それは配列と同じサイズを持つことになり、スペースの局所性を保証するスタックに割り当てられます。

typedef struct { 
    int arr[5]; 
} my_array1; 

typedef struct { 
    int values[3]; 
} factorFunctionReturnType_t; 

第二の回避策は、スタティックメモリプールを(例えば、この配列のみの自由なカスタムのmalloc /持つ配列)を発明することであり、これは効果的に効果的に戻って、あなたが動的に再び、このプールからメモリを割り当てることができます連続したスタック空間へのポインタ。定義上は配列です。

#include <stdint.h> 
static uint8_t static_pool[2048]; 

その後、再び作成し、メモリがスタック上にあることを確実にすること、およびメモリは、すでにアプリケーションアプリオリによって所有され、この特定のメモリプールを管理my_freeをmy_allocを実装(malloc関数によって以前にアクセスすることはできませんメモリを割り当てる可能性があるのに対し、十分なメモリがない場合はクラッシュ、失敗した場合はチェックしませんでした)。

第3の回避策は、関数がローカル変数をコールバック関数に返すようにすることです。これにより、関数を終了すると、メモリを使用する関数がスタックを含むスコープの上にあるため、スタックを破損することなく結果を使用できます。

#include <stdint.h> 
#include <stdio.h> 

void returnsAnArray(void (*accept)(void *)) { 
    char result[] = "Hello, World!";  

    accept(result); 
} 

void on_accept(void *result) { 
    puts((char *)result); 
} 

int main(int argc, char **argv) 
{ 
    returnsAnArray(on_accept); 

    return 0; 
} 

これは、断片化を避けるために意思決定を行う必要がある非stacklikeメモリプール、それは必要がないため、単にスタックの先頭に結果を置くstacklikeメモリプールよりも効率よりも効率的です文字列をコピーし、関数の戻り値が(ロックが使用されていない限り)別のスレッドによって上書きされる危険性がないため、スレッドセーフです。

面白いのは、すべての "機能プログラミングパラダイム"プログラムは、コールバック関数を連鎖させることによってmallocなしでCプログラムを書くことができ、スタックに効果的に割り当てることができるということです。

これは、リンクリストを敵対的なキャッシュにしないという面白い副作用があります(スタックに割り当てられたコールバックリンクリストはすべてスタック上で互いに近くなるため、実行時文字列操作のようなことはありませんmallocを実行することなく、未知のサイズのユーザ入力を構築することができます。

0

まず、Cの関数から配列を直接返すことはできません。できることは、配列のアドレスその場合、関数は次のようになります。

int* test(int size, int x){ 

    /* function body */ 

    return factorFunction; 
} 

配列を受け取ると、配列ではなくポインタが必要になります。

int factors[2];の代わりに、main機能でint *factors;を使用する必要があります。

第2に、配列のアドレスを返しても、このコードは機能しません。ローカル配列のアドレスを返そうとしているためです。関数の実行後には存在しません。この問題を解決する簡単な方法の1つは、ローカル配列(この場合はfactorFunction)を静的に宣言することです。

これら二つの事項を考慮すると、機能testは次のようになります。

int* test(int size, int x){ 

    static int factorFunction[size]; 

    /* function body */ 

    return factorFunction; 
} 
1

Cは、ローカルに定義する必要がありますので、関数の外に、ローカル変数のアドレスを返すために提唱していません静的変数としての変数。

#include <stdio.h> 

/* function to generate and return random numbers */ 
int * getRandom() { 

    static int r[10]; 
    int i; 

    /* set the seed */ 
    srand((unsigned)time(NULL)); 

    for (i = 0; i < 10; ++i) { 
     r[i] = rand(); 
     printf("r[%d] = %d\n", i, r[i]); 
    } 

    return r; 
} 

/* main function to call above defined function */ 
int main() { 

    /* a pointer to an int */ 
    int *p; 
    int i; 

    p = getRandom(); 

    for (i = 0; i < 10; i++) { 
     printf("*(p + %d) : %d\n", i, *(p + i)); 
    } 

    return 0; 
} 
関連する問題