编程语言基础 C语言 递归 数组 结构体

C言語における以下の問に答えよ。以下のプログラムにおいて,\(バックスラッシュ)は¥(円記号)と同じである。

[1] 次のプログラムの表示結果を示せ。

int main(void){
    int a=0x468a; char b[]="pqrstu";
    printf("  %x\n  %x\n %x\n", a++, ++a, a--);
    printf("  %c\n  %s\n", b[3], &b[2]);
    return 0;
}

[2] 大きさがnである整数型1次元配列aの各要素には1から9までの整数がランダムに代入されている。xを1から9までのいずれかの値をとる整数とする。x, a, aの大きさnを引数として受け取り,xと同じ値が代入されたaの要素に0を代入する関数fnc1を再帰的プログラミングで作成した。下線部に入れるべき式,または式の一部を答えよ。

int fnc1(int a[], int n, int x){
    if( _____(1)_____ ) a[n]=0;
    if(n>0){
        return fnc1( _____(2)_____ );
    }else{
        _____(3)_____ ;
    }
}

[3] n行n列の正方行列のすべての要素の和を計算する関数fnc2を作成せよ。正方行列の要素は実数型2次元配列aに代入される。fnc2は,aとaの大きさnを引数として受け取り,演算結果をreturn文で返す。aの最大サイズをNとする。ただし,nNである。fnc2を利用するmain関数を以下に示すので,これにあわせてfnc2を作成せよ。

#include<stdio.h>
#define N 10
int main(void){
    float a[N][N]={{1,10},{2,100}}, n=2;
    printf("%f\n", fnc2(a,n));
    return 0;
}

[4] 文字型配列nameと整数型変数ageをメンバーとする構造体exmを定義せよ。

[5] 問題[4]で定義した構造体を用いて,サイズnの配列memを定義した。memのメンバーnameには氏名が,メンバーageには年齢が代入されている。ageの値が整数変数zの値と等しいmemの要素のnameをディスプレイに表示する関数fnc3を作成した。下線部に入れるべき式,または式の一部を答えよ。

int fnc3(struct exm mem[], int n, int z){
    _____(4)_____
    for(i=0; i<n; i++){
        if( _____(5)_____ == z) printf( `_____(6)_____` );
    }
    return 0;
}

解答:

[1]
C言語における関数の引数の評価順序は未規定であるが、一般的に右から左へ評価されることが多い(gccなどの環境)。しかし、同一式内で副作用を伴う演算子(++, --)を複数回適用した場合の動作は未定義(undefined behavior)であるため、厳密な出力結果は処理系依存となる。ここでは、右から左へ評価され、副作用が各引数の評価直後に適用されると仮定して解答を示す。
初期値:

  1. a-- が評価される: 値は 、その後 になる。
  2. ++a が評価される: になり、値は
  3. a++ が評価される: 値は 、その後 になる。
    (※ただし、出力順は左から a++, ++a, a-- の順)
    したがって、1つ目のprintfの出力は 468a, 468a, 468a となる。
    (※注意: 処理系によっては 4689, 468a, 468a など異なる結果になる可能性がある)

b[] = "pqrstu" について、b[0]='p', b[1]='q', b[2]='r', b[3]='s', b[4]='t', b[5]='u', b[6]='\0'
b[3] は文字 's'
&b[2] はインデックス2からの文字列なので "rstu"

(注: 1つ目の出力は処理系依存の解釈の1つ)

[2]
配列のインデックスは通常 から までである。引数 n は処理する要素のインデックスを表すと考えられるため、呼び出し元で が渡されるか、関数内で を処理していく。コードの構造から、現在のインデックス n の要素をチェックし、n>0 の間再帰呼び出しを行い、n=0 を処理したら終了する形になっている。

(1) 現在の要素 a[n]x と等しいか判定する。
(2) 次の要素を処理するために、インデックスを n-1 にして再帰呼び出しを行う。
(3) 再帰の終了条件を満たした(n が 0 以下になった)ときに返す値。戻り値の型が int なので、通常は 0 などを返す。

[3]
2次元配列を引数に取る際、列数は定数で指定する必要がある。

[4]

(文字配列のサイズは任意であるが、実用的な適当な値を設定する)

[5]
(4) forループで使用する変数 i を宣言する。
(5) 構造体配列 memi 番目の要素の age メンバにアクセスする。
(6) 構造体配列 memi 番目の要素の name メンバを文字列として出力する。


这道题目主要考察了C语言的几个核心基础概念。第一题涉及指针运算、自增自减运算符以及函数参数求值顺序,需要特别注意的是C语言标准对于函数参数列表中多次修改同一变量的行为并没有明确规定求值顺序,属于未定义行为,实际输出结果会由于编译器的不同而产生差异。第二题考察了递归函数的编写逻辑,要填空的部分分别是递归时的条件判断、进入下一层递归时的参数传递以及到达递归基时的返回值。第三题考察了多维数组作为函数参数的传递方法,当二维数组作为参数传递时,除了第一维之外的其他维度的大小必须明确给出。第四题和第五题考察了结构体的定义以及结构体数组的应用,重点在于如何通过点运算符访问结构体数组中特定元素的成员变量,并在循环中进行条件判断和输出。