C言語の配列、ローカルに確保した場合
対象
内容
またC言語の配列の話(笑)。
今回は、ローカルに配列を確保した場合について。
#include<stdio.h>
char* func1(){
char array[] = {'a', 'b', 'c'};
return array; // Don't do this!
}
int main(){
printf("array: %s\n", func1()); // not correct!
}上のコードはやっちゃ駄目な例。配列は、ローカル変数でスタックに保持されて、関数から抜けたらそのメモリ領域の確保は解除されてしまいます。当たり前と言えば当たり前なんですけどね。このコード、実際には警告付きでコンパイルされて、(nil) とかで表記されたりする時もありますが、printf に渡されるのは実は何だか分かりません。
でも、この関数の中でしか使えない訳ではなく、そこから呼ぶ関数には渡せます。
#include<stdio.h>
void func_child(char array[]){
printf("in child func: %s\n", array); // OK! 'abc' is correctly shown
}
int main(){
char array[] = {'a', 'b', 'c'};
func_child(array);
}関数が確保したローカル変数の領域は、関数を出るまで有効なので。
ですが、文字列のリテラル使用の場合、似てる様でいて似てません。上の様に配列の中に入れてやるとローカル保持ですが、以下の様に文字列をリテラルとし、ポインタ渡しで返した場合は動きが違うんですよね。こちらは関数から出てもオッケー。
#include<stdio.h>
char *func(){
char *ptr = "abc";
return ptr; // OK!
}
void main(){
printf("array: %s\n", func()); // "abc" is correctly shown
}上の例は、文字列リテラルである"abc" が、静的領域に置かれて、そこのアドレスを ptr ポインタ変数が持つという意味で、そのポインタの中身をコピーして返してる。文字列リテラルは、ローカルのスタック領域に置かれるのではない。ptr ポインタはローカルのスタック領域に確保されるんですが、中身を値渡しなのでOK。
これを char array[] と配列型にして返すと動きません。
#include<stdio.h>
char *func(){
char array[] = "abc";
return array; // Don't do this!
}
int main(){
printf("array: %s\n", func());
}配列型の場合は、関数ローカルのスタックに"abc"分の領域が保持されて、そのアドレスを array が指す様になります。なので関数から出ると使えません。上のコードは、char array[]; として、array[0] = 'a'; array[1] = 'b'; ... としているのと同じで、char *ptr = "abc" とは動きが全く別って事みたいなんですよね。
意外と深いと思う C 言語の配列の話。