17

以下に示すように、配列名を返そうとしました。基本的に、関数テストがメインで使用できる配列を返すようにしようとしています。このような機能を実行する方法を見つけるために、さらに何を読む必要があるか教えていただけますか?

#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
4

14 に答える 14

15

C では、関数は配列を返すことができません。

ただし、構造体を返すことはできます。また、構造体には配列を含めることができます...

于 2013-01-12T19:38:57.023 に答える
14

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

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

コードには別の問題もあります。それは、サイズ 2 の配列を使用しているが、3 番目の要素に書き込むことです。

于 2013-01-12T19:42:17.517 に答える
9

ヒープにメモリを割り当て、ポインターを返す必要があります。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;
}
于 2013-01-12T19:40:15.140 に答える
3

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

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

例えば

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

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

2 番目の回避策は、静的メモリ プール (たとえば、この配列のみのカスタム malloc/free を持つ配列) を発明することです。これにより、効果的にこのプールからメモリを動的に割り当てることができるようになり、連続したスタック空間へのポインタが効果的に返されます。定義上、配列です。

例えば

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

次に、この特定のメモリ プールを管理する my_alloc、my_free を実装し、作成されたメモリがスタック上にあり、そのメモリがアプリオリにアプリケーションによって既に所有されていることを確認します (一方、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;
}

これは、フラグメンテーションを回避するために決定を行う必要がある非スタックのようなメモリ プールよりも効率的です。また、文字列をコピーする必要がないため、結果をスタックの一番上に置くだけのスタックのようなメモリ プールよりも効率的です。関数の戻り値が別のスレッドによって上書きされるリスクがないため (ロックが使用されない限り)、スレッドセーフです。

面白いことに、すべての「関数型プログラミング パラダイム」プログラムは、コールバック関数を連鎖させ、効果的にスタックに割り当てることで、malloc なしで C プログラムを記述できることを強調することになります。

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

于 2016-08-27T17:21:36.183 に答える
3

エラー メッセージの最初の行は、まさにその内容を意味しています。関数を を返すように宣言しましたがint、ポインタを返そうとしています。
より大きな問題 (エラー メッセージの 2 行目でわかるように) は、ポインターを返そうとしている配列がローカル配列であるため、関数が返されたときにスコープ外になり、有効ではなくなることです。
あなたがすべきことは、mallocorを使用して配列 (つまり、連続メモリのチャンク) を動的に割り当て、newそれへのポインタを返すことです。そしてもちろん、使い終わったら必ずメモリを解放してください。

于 2013-01-12T19:41:03.413 に答える
2

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;
}
于 2017-11-02T10:23:23.330 に答える
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]配列の外に出ます。

于 2013-01-12T20:05:02.123 に答える
0

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

int* test(int size, int x){

    /* function body */

    return factorFunction;
}

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

したがって、使用する代わりに、関数でint factors[2];使用する必要があります。int *factors;main

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

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

int* test(int size, int x){

    static int factorFunction[size];

    /* function body */

    return factorFunction;
}
于 2016-10-29T15:53:24.480 に答える
0

配列を返す別の方法を次に示します。

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

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

于 2015-10-21T13:57:48.823 に答える
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;
}

上記のように、設定しているインデックスが実際に配列に存在することを確認することもできます

于 2013-01-12T19:45:38.847 に答える
0

まず、 VLAを持つ C99 を使用していない限り、配列サイズは C で一定である必要があります。以下のステートメントは使用できません。

int factorFunction[size];

次に、スコープから削除される関数で作成された配列を返そうとしています。

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

于 2013-01-12T19:45:39.830 に答える
0
  // example for to create a array in function and it return using pointer
  //if you want use malloc use header #include <stdlib.h>
      int * printsquares(int a[],int size){  //to declare aa function

      int* e = malloc(sizeof(int) * size);  //to create array using malloc
       for(int i=0;i<size;i++){    
             e[i]=i*i;       //assign the square root values
      }



   return e;


 }
于 2020-02-07T11:46:32.943 に答える
-1

ユーザー定義関数からメイン関数に配列を返す方法に関する非常に基本的なコードの説明が役立つことを願っています。以下に、作成する完全なコードを書きました。C++ 言語をご容赦ください。ただし、正確に C プログラムが必要な場合は、お気軽にコメントしてください。

#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
}
于 2015-01-29T11:19:26.040 に答える