ホーム » 「C言語」タグがついた投稿

タグアーカイブ: C言語

2018年12月
« 11月    
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

最近の投稿(電子情報)

アーカイブ

カテゴリー

局所変数配列をreturn

情報構造論の前期期末試験で、局所変数返しの解答が多かったので、メモ。

JavaScript でプログラムを書いていると、動くネタだけど、C言語では初心者がよく間違って書いてしまう定番であり、それなりに動いたりするから、誤解が増えてしまう可能性もある。

スタック変数返し

char* foo() {
   char str[ 20 ] ;
   strcpy( str , "Hello World" ) ;
   return str ;
}
char* bar() {
   char baz[ 20 ] ;
   memset( baz , 'A' , sizeof( baz ) ) ;
   return NULL ;
}
void main() {
   char* ans = foo() ;
   printf( "%s¥n" , ans ) ; // Hello World
   // 一見正しく動いているように思うかも。

   bar() ; // 局所変数を触るだけの処理
   printf( "%s¥n" , ans ) ; // AAAAAAAAAAA
   // ans の中身が壊れている。
}

静的局所変数返し

上記のスタック変数を返す問題点を示すと、じゃあ静的局所変数でいいじゃん….という話がでてくる。

char* foo() {
   static char str[20] ;
   strcpy( str , "Hello World" ) ;
   return str ;
}

この方式なら、スタック領域ではなく静的変数領域なので、関数呼び出しで破壊されることはない。
しかし、この方式は「スレッドセーフ」ではない。foo() の処理後に、スレッドを起動した場合、スレッドではメモリ空間が共有されるため、foo() を保持していて、別スレッドがそのメモリを書き換えると、他方は中身が変わってしまう。
(参考「スレッドセーフではないCライブラリ関数」)

実数と整数の変換

情報制御基礎で出題した問題で、5点の移動平均の処理の一部に、以下のコードがあった場合の間違い説明の問題。

int avg() {
   int s = .... ;
   return (1/5) * s ;
}

の間違いを修正せよ….の答えだけど、return 0.2 * s ; とか return s/5 ; が答えだけど、小数点以下が切り捨てになるのか、四捨五入になるのか気になってきた。

for( double x = 0.0 ; x <= 2.0 ; x += 0.1 )
   printf( "%ld %d\n" , x , (int)x ) ;

で確認してみたら、(int)実数は、小数点以下切り捨てだな。となると、四捨五入したいなら、return (int)( 0.2 * s + 0.5 ) ; とか、return (s+2)/5 ; とか書いてほしい…とか微妙な話になるな。

採点は、切り捨て・四捨五入の誤差については問わないで、0.2*s , s/5 を◯でいこう。