web-dev-qa-db-ja.com

Cの関数で配列を変更しますか?

関数を呼び出したいのですが、その関数でプログラムの文字列または配列の内容を定数に変更します。

擬似コード:

some_array = "hello"
print some_array   #prints "hello"
changeArray(some_array)
print some_array  #prints "bingo"

その関数へのポインタを渡す必要があることはわかっています。これが私が書いたものです、

void changeArray(char *arr){
    arr = "bingo";
}

int main(int argc, const char* argv[]){
    char *blah = "hello";
    printf("Array is %s\n",blah);
    changeArray(blah);
    printf("Array is %s\n",blah);
    return EXIT_SUCCESS;
}

これどうやってするの?

15
Alex

参照ではなく値で配列へのポインタを渡している。そのはず:

_void changeArray(char **arr){
    *arr = "bingo";
}

int main(int argc, const char* argv[]){
    char *blah = "hello";
    printf("Array is %s\n",blah);
    changeArray(&blah);
    printf("Array is %s\n",blah);
    return EXIT_SUCCESS;
}
_

"hello"のアドレスをchangeArray関数に渡しましたが、関数で元のポインターではなく、渡された値を変更しました。私が行った変更はポインターのアドレスを渡し、ポインター自体は関数内で変更されます。

_char *blah = "hello";_は、定数文字列へのポインタと_*arr = "bingo";_を定義しないでください。どちらも問題ありませんが、文字列自体を変更することを検討する場合は、できません。

編集:

関数に引数を渡した場合でも、ポインターであっても、関数がそこから読み取った場所(通常はスタック)に実際に引数をコピーします。引数自体を渡すのではなく、そのコピーを渡します。関数がそれを変更すると(_arr = "bingo";_のように)、元の変数ではなく、変数のコピーが変更されます。したがって、変数自体を変更するために、変数のアドレスを関数に渡します(changeArray(&blah);-_&_は_address of-_を意味します)。関数では、格納されている変数を変更します渡したアドレス(_*arr = "bingo";_-_*_はアドレスarrの変数を意味します)。

元のblahポインタがアドレス0x00000000にあり、_"hello"_文字列のアドレス(たとえば0x00000010)を含んでいると仮定します。関数にblahを渡すと、たとえば、アドレス0x00000020にある新しい変数arrにコピーします。

_Variable    Address     content
-------------------------------
blah       00000000    00000010   (points to hello)
"hello"    00000010    "hello" (this is just an example, so don't be hard on me :) )
arr        00000020    00000010
"bingo"    00000030    "bingo" (and again...)
_

ここで、arrの内容を変更すると、アドレス0x00000020の値は変更されますが、アドレス0x000000000の値は変更されないため、blahには依然として00000010が含まれます。

_Variable    Address     content
-------------------------------
blah       00000000    00000010   (points to hello)
"hello"    00000010    "hello" (this is just an example, so don't be hard on me :) )
arr        00000020    00000030 (points to "bingo")
"bingo"    00000030    "bingo" (and again...)
_

代わりに、blahのアドレス(0x00000000)をarrにコピーし、関数内で次のように記述します-"arrのcontentは- address、このアドレスに移動し、そのコンテンツを「bingo」文字列を指すように変更します。したがって、アドレス0x00000000(blah)のコンテンツは「bingo」を指しています。

_Variable    Address     content
-------------------------------
blah       00000000    00000030   (points to "bingo")
"hello"    00000010    "hello"    (this is just an example, so don't be hard on me :) )
arr        00000020    00000000   (points to `blah`)
"bingo"    00000030    "bingo"    (and again...)
_

私があなたを混乱させなかったことを願っています...

32
MByD

コードに配列はありません。実際にblah文字ポインターが指すものを変更しようとしている場合は、ポインターを関数へのポインターに渡す必要があります。ただし、配列を使用してこれを行う場合は、次のようにする必要があります。

void changeArray(char arr[]) {
  // or you can use char *arr, it's the same thing from
  // the C compiler's point of view
  strcpy(arr, "blah");
  // alternatively, you could set each element. i.e. arr[0] = 'b';
}

int main (int argc, char** argv) {
  char blah[100] = "hello"; // this is an array
  printf("Array is %s\n", blah);
  changeArray(blah);   // array decays to pointer
  printf("Array is %s\n", blah);
  return EXIT_SUCCESS;
}
7
Ferruccio

配列自体ではなく、配列へのポインタを渡す必要があります。

別のこと:関数に制御条件を追加します。考えてみましょう:「bingo」がstrlen(some_array)よりも大きくなるとどうなりますか? Cでは配列サイズを動的にする必要がある場合はmallocする必要があるため、エラーが発生します。

0
Batman