

C言語を勉強中の者です。  
参考書にて下記のmalloc関数のプログラムが書かれていたのですが、  
`str = (char *)`の部分から何がどう行われているのかわかりません。

説明できる方よろしくお願いいたします。

[code]

    #include<stdio.h>
    #include<stdlib.h>
    
    int main(void)
    {
       char *str;
       int num,i;
    
       printf("何文字のAを用意しますか？\n");
       scanf("%d",&num);
    
       str = (char *)malloc(sizeof(char) * (num+1));
       if(!str){
         printf("メモリを確保できませんでした。\n");
         return 1;
       }
    
    
       for(i=0;i<num;i++){
           *(str+1) = 'A';
       }
       *(str+num) = '\n;
       printf("%sを用意できました。\n",str);
    
       free(str);
    
       return 0;
    }
    
[/code]


CC BY-SA 4.0
2019-07-04T07:35:59.843
56377
2019-08-08T16:00:38.217
2019-07-04T08:07:49.020
76
34879
question
c
malloc関数について


これでコンパイルしてみてください。

[code]

    #include<stdio.h>
    #include<stdlib.h>
    
    int main(void)
    {
       char *str;
       int num,i;
    
       printf("何文字のAを用意しますか？\n");
       scanf("%d",&num);
    
       str = (char *)malloc(sizeof(char) * (num+1));
    
       printf("アドレス %p に %d 文字 + 1 分の　データ領域を確保しました。\n",str,num);
    
       if(!str){
         printf("データ領域（メモリ）を確保できませんでした。\n");
         return 1;
       }
    
    
       for(i=0;i<num;i++){
    
         printf("アドレス %p に A を書き込みます\n",str+i);
    
           *(str+i) = 'A';
       }
       printf("アドレス %p に null ('\\0') を書き込みます\n",str+num);
    
       *(str+num) = '\0';
    
       printf("%s\n",str);
       printf("を用意できました。\n");
    
       free(str);
    
       return 0;
    }
    
[/code]


CC BY-SA 4.0
2019-07-04T08:04:23.403
56381
2019-07-04T08:08:11.527
2019-07-04T08:08:11.527
29826
34980
56377
answer


`malloc()` の話をする前に確認事項ですが [c](/questions/tagged/c "'c' のタグが付いた質問を表示")
において「文字列」とは

  * `char` の配列、ないしは相当する連続領域で
  * `'\0'` 文字で終了するもの
  * があるとき、その先頭アドレス（先頭要素へのポインタ右辺値）をもって「文字列」とする

です。

[code]

    char hello[] = "Hello!";
    
[/code]

であれば真に配列です。コンパイラが、ソースコード上には書かれていない `'\0'` 文字を `!`
の後ろにくっつけることを行っているので、先の「文字列」の条件を満たしています。ちなみに、この配列変数 `hello` は合計７文字分の配列となります。

さて `malloc(n)` が何をするかというと

  * 最低 `n` バイトの連続したメモリ領域をどこかに取得します
  * ここでいう「バイト」とは `char` １個が格納できる大きさのことを言います
  * その先頭アドレス（先頭要素へのポインタ右辺値）を返却します
  * よって `malloc(n)` が返してきた値（＝連続メモリ領域）には最低 `n` 文字が格納できます
  * (最低 `n` 文字ということは) `n+1` 文字は格納できない前提で処理を行う必要がある

ここまで、先の「文字列」の条件の最初と最後のものに合致していますよね。更に「文字列」のもう一つの条件である `'\0'` があることを満たしてやれば
`malloc()` の結果を「文字列」として扱うことができます。

  * `num` 文字の `'A'` を格納し
  * その後ろに `'\0'` を追加格納したい
  * のであれば `malloc()` の引数には `num+1` を渡す必要がある

とまでわかれば解説になるでしょうか。


CC BY-SA 4.0
2019-07-05T00:59:22.637
56405
2019-07-05T00:59:22.637
8589
56377
answer


コメントを加えてみました。  
参考になれば幸いです。

[code]

    #include<stdio.h>
    #include<stdlib.h>
    
    int
    main(void) {
        // 変数を宣言しています
        char *str;
        int num, i;
    
        // ユーザーからの入力を受け付けています
        // 変数numに用意するAの個数が入力されます
        printf("何文字のAを用意しますか？\n");
        scanf("%d", &num);
    
        // 本来ならここら辺で入力値のバリデーションを行うべきですが何もしていないようです
    
        // char *型のポインタ変数strに、mallocで確保したメモリのアドレスを代入しています
        // 
        // mallocの引数には確保するメモリのバイト数を渡します
        // sizeof(char)でcharのバイト数がわかります
        // そのバイト数に(num+1)分の値をかけています
        // charのバイト数は1バイトなのでnumが10だった場合、1*(10+1)、つまり11バイト分のメモリが確保されます
        // (num+1)で+1しているのは文字列を終端するnull文字のためです
        // 
        // mallocは戻り値でvoid *を返します
        // このコードでは明示的にmallocの戻り値を(char *)でキャストしているようです
        // Cでは暗黙の型変換が行われるので、このキャストを外しても動作には影響がありません
        str = (char *)malloc(sizeof(char) * (num+1));
    
        // mallocの戻り値をチェックしています
        // mallocはメモリの確保に失敗したときにNULLを返します
        // NULLの定義は処理系依存ですが(void *)0で表現されることが多いです
        // 
        // if (!str) {}
        // 
        // このif文はstrがNULLだった時に真になります
        // つまり、メモリの確保に失敗したら真になります
        if(!str){
            // メモリの確保に失敗しているのでエラーメッセージを表示しています
            // 普通はstderrに出力しますが、このコードではstdoutに出力しているようです
            printf("メモリを確保できませんでした。\n");
    
            // プログラムの処理に失敗したので1を返します
            // main関数では成功時に0、失敗時にそれ以外を返します
            // この値はbashなどではecho $?で確認できます
            return 1;
        }
    
        // for文でstrに値をセットしているようです
        // しかし、このfor文の内容はあまり意味がありません
        // ループをnum回まわしていますが、やってることは無意味です
        // *(str+1) は str[1] のシンタックスシュガーです
        // つまり、*(str+1)はstr[1]と同じです
        // 添え字が1なので、ループで回してもずっとstr[1]にアクセスしています
        // str[1]に文字'A'がnum回分代入されます
        // 
        // おそらくこれはstr[i]の間違いでしょう
        // str[i] = 'A'
        // にすればstrの0からnum-1までに文字'A'が代入されます
        for(i = 0; i < num; i++){
            *(str+1) = 'A';
        }
    
        // strのnum文字目に改行を代入しています
        // *(str+num) は str[num] と同じです
        // 
        // おそらくですが、これは
        // *(str+num) = '\0'
        // の間違いでしょう
        *(str+num) = '\n';
    
        // 初期化したstrを出力していますが、この出力はうまくいきません
        // mallocはメモリを初期化せずに確保します
        // つまり、確保したメモリにはデタラメな値が入っています
        // Cの文字列はnull終端されていないとただしく出力できません
        // 今までの処理の中でnull文字を代入している処理はないので、printfは正しく機能しません
        // 
        // 正しく機能させるには
        // str[num] = '\0'
        // でstrをnull終端する必要があります
        printf("%sを用意できました。\n",str);
    
        // 確保したメモリを開放しています
        free(str);
    
        return 0;
    }
    
[/code]


CC BY-SA 4.0
2019-07-08T11:14:26.233
56497
2019-07-08T11:30:35.790
2019-07-08T11:30:35.790
25852
25852
56377
answer