List11-4 のプログラムをもとに,以下の変更を加えなさい。ただし,アドレス演算子 & は使用しないコードを考えてください。
  1. "LISP"の先頭要素のアドレス,"C"の先頭要素のアドレス,"Ada"の先頭要素のアドレスを,それぞれ,charへのポインタ型であるp[0],p[1],p[2]へ代入するコードを追加してください。コードを追加する場所は,変数の型宣言文(char *p[3] = {"PAUL", "X", "MAC"};)の直後にしてください。
  2. その後に,"LISP"の先頭要素のアドレス,"C"の先頭要素のアドレス,"Ada"の先頭要素のアドレスを,それぞれ表示するコードを追加してください。その際,変数aを使うコードと,変数pを使うコードの,二通りのコードを追加してください。


教員からの解答例


/*
    文字列の配列
*/

#include <stdio.h>

int main(void)
{
    int i; 
    char a[][5] = {"LISP", "C", "Ada"};
    char *p[] = {"PAUL", "X", "MAC"};



    /* "LISP", "C", "Ada"のそれぞれの先頭要素のアドレスをp[]に代入 */
    for(i = 0; i < 3; i++)
        p[i] = a[i];/* a[i] とすると,2次元配列a[][]の,i行目の先頭部分のアドレスを取り出せる。
                       それを,ポインタ型の変数p[i]に,代入すればよい。 */

    /* 変換指定子を%pとすると,a[0]やp[0]などを,ポインタ型変数と見なし,
       その入れ物に入っている値(すなわちアドレス値)を画面表示する */
    printf("\"LISP\"の先頭要素のアドレス(a[0][0]のアドレス):%p\n", a[0]);
    printf("\"LISP\"の先頭要素のアドレス(p[0]の値そのもの):%p\n", p[0]);

    printf("\"C\"の先頭要素のアドレス(a[1][0]のアドレス):%p\n", a[1]);
    printf("\"C\"の先頭要素のアドレス(p[1]の値そのもの):%p\n", p[1]);

    printf("\"Ada\"の先頭要素のアドレス(a[2][0]のアドレス):%p\n", a[2]);
    printf("\"Ada\"の先頭要素のアドレス(p[2]の値そのもの):%p\n", p[2]);
    /* 追加コードここまで */



    for(i = 0; i < 3; i++)
        /* 変換指定子を%sとすると,a[0]やp[0]などを,char型の配列名と見なし,
           その配列の各要素に入っている値(すなわち文字)を,ナル文字にぶつかるまで,画面表示しつづける */
        printf("a[%d] = \"%s\"\n", i, a[i]);

    for(i = 0; i < 3; i++)
        printf("p[%d] = \"%s\"\n", i, p[i]);

    return (0);
}

間違いの例その1


#include <stdio.h>
int main(void)
{
int i;
char a[][5]={"LISP","C","Ada"};
char *p[]={"PAUL","X","MAC"};

for (i=0;i<3;i++)
 p[i]=a[i];

for(i=0;i<3;i++){
 printf("&a[%d]=%p\n",i,a+i);
 printf("&p[%d]=%p\n",i,p+i); // *(p+i) としなければならぬ。注意! 理由は以下の図面を参照せよ。

 printf("a[%d]=\"%s\"\n",i,a[i]);
 printf("p[%d]=\"%s\"\n",i,p[i]);
 }

return 0;
}


間違いの例その2

アドレス演算子 & を使用している例(問題文をよく読みなさい!)

/*
    文字列の配列
*/

#include <stdio.h>

int main(void)
{
    int   i;
    char  a[][6] = {"LISP", "C", "Ada"};
    char  *p[]   = {"PAUL", "X", "MAC"};

    p[0] = &a[0][0]; /* アドレス演算子 & を使用するとすれば,このようにできます。
                        だが,問題は, & を使用せずに同じことを実現して下さいということです。注意! */
    p[1] = &a[1][0];
    p[2] = &a[2][0];

    printf("\"LISP\"の先頭アドレス(a):%p\n", &a[0][0]);/* ここも,アドレス演算子 & を使用するとすれば,このようにできます。
                                                         & を使用しないとすればどうなるか考えて下さい。
                                                         (&a[0][0]と同じ値が入っているのは何ですか?)
                                                               ↑
                                                         このようなことを頭を使って考えることが,そのまま定期試験勉強になるんです! */
    printf("\"LISP\"の先頭アドレス(p):%p\n", p[0]);
    printf("\"C\"の先頭アドレス(a):%p\n", &a[1][0]);
    printf("\"C\"の先頭アドレス(p):%p\n", p[1]);
    printf("\"Ada\"の先頭アドレス(a):%p\n", &a[2][0]);
    printf("\"Ada\"の先頭アドレス(p):%p\n", p[2]);

    for (i = 0; i < 3; i++)
        printf("a[%d] = \"%s\"\n", i, a[i]);

    for (i = 0; i < 3; i++)
        printf("p[%d] = \"%s\"\n", i, p[i]);

    return(0);
}


テキスト298ページの演習11-4

教員からの解答例


/*
    文字列を走査して表示する
*/

#include <stdio.h>

/*--- 文字列を表示(改行はしない) ---*/
void put_string(const char *s)
{
    while(*s)
        putchar(*s++); /* charへのポインタ型 s の指している値 *s (char型,すなわち1文字)を表示し,それからsの値が一つ増える (s++) 。
                          後置増分演算子 ++ と間接演算子 * では,後置増分演算子のほうが優先順位が高いが,
                          後置増分演算子 s++ は,sの値が増える前の値を返すので,結果としては上記のような順番の動作となる。
                          s は,charへのポインタ型であると同時に,char型を要素とする配列の配列名として扱うこともできる。
                          sの値を一つ増やすと,配列 s の一つ後ろの要素のアドレスを指すことになる。 */
}

int main (void)
{
    char str[128];

    printf("文字列を入力してください:");
    scanf("%s", str);

    printf("あなたは") ;
    put_string(str);
    printf("と入力しました。\n");

    return(0);
}


テキスト303ページの演習11-7

教員からの解答例


/*
    文字列内の英字を大文字/小文字に変換
*/

#include <ctype.h>
#include <stdio.h>

/*--- 文字列内の英字を大文字に変換 ---*/
void str_toupper(char *str)
{

    while(*str){
        *str = toupper(*str); /* charへのポインタ型 str の指している値 *str を関数toupper()で大文字にして,
                                 その戻り値を,*str に代入している。 */

        str++; /* charへのポインタ型strを一つインクリメントしている。 */
    }
    
}

/*--- 文字列内の英字を小文字に変換 ---*/
void str_tolower(char *str)
{

    while(*str){
        *str = tolower(*str);
        str++;
    }
    
}

int main(void)
{
    char str[128];

    printf("文字列を入力してください:");
    scanf("%s", str);

    str_toupper(str);
    printf("大文字:%s\n", str);

    str_tolower(str);
    printf("小文字:%s\n", str);

    return(0);
}