strcpyで最近よく間違えること。

# 同じミスを繰り返すのでメモ

## Cでよくこんな感じのコードを書く。

そして、Segmentation fault(コアダンプ)と表示されてしばらく悩む(^_^;)
gdbでデバッグ始めて、落ちてる場所特定して、で終われば良いんだけど、そこじゃないところで落ちてるように見えるんで、さらに悩む。

```c:test.c

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char OrgMessage[] = "Original Message";
    char *temp = NULL;

    strcpy(temp, OrgMessage);

    printf("%s\r\n", temp);

    return 0;
}
```

*正しくはこっち*

```c:test.c 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char OrgMessage[] = "Original Message";
    char *temp = NULL;

    /* '\0'を含んだサイズを確保するから[+1]は不要！ @shiracamusさん
    temp = (char*)malloc(sizeof(char) * sizeof(OrgMessage) + 1);
    */
    temp = (char*)malloc(sizeof(char) * sizeof(OrgMessage));

    if(temp == NULL){
        printf("failed malloc\r\n");
        /* コメントからエラーの場合は終わらせよう！@fujitanozomuさん */
        exit(EXIT_FAILURE); 
    }

    strcpy(temp, OrgMessage);

    printf("%s\r\n", temp);

    free(temp);

    return 0;
}
```
ただのポインタのtempに文字列コピーしようとして0アクセスしてるのが原因。
ちゃんとサイズを確保しよう。

**先輩より**
strcpy(), strncpy(), strlcpy(), strdup(), strndup()どれを使うにしても、
コピー先が十分大きくないとデータが捨てられてしまうので、作りたいものを検討してから
どの関数が適当か考えましょう。

データ捨てられてダメなら、どの関数使おうが関係無く、その手前で判定入れようね！
とのことでした(^_^;)

## コンパイラと環境
(Windows 7 64bit, cygwin 2.4.1)

```
gcc --version
gcc(GCC) 5.3.0

gcc -Wall test.c

./a.exe
Original Message

```

## 追記(strncpy()版)

せっかくコメントいただいたので調べたことをメモ。
strlcpyは標準に含まれていないようなので今回は見送り(/_;)
strcpy()は'\0'までをコピーしてくれますが、終端文字'\0'が無ければいくらでも(?)コピーしてメモリ壊してくれます。
そのため、strncpy()を推奨。
できればstrlcpy()を使いましょう。(標準ではありません。)


```c:test.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char OrgMessage[] = "Original Message";
    char *temp = NULL;
    int i;

    /* tempのサイズは、"Original Message" + '\0' 分 */
    temp = (char*)malloc(sizeof(char) * sizeof(OrgMessage));

    if(temp == NULL){
        printf("failed malloc\r\n");
        /* malloc失敗したら止める */
        exit(EXIT_FAILURE); 
    }
    /* strlenは'\0'を含まないサイズを返す。 */
    /* strncpyはOrgMessageより大きいsizeを指定すると'\0'で残りを埋める。 */
    strncpy(temp, OrgMessage, strlen(OrgMessage) + 1);
    
    printf("%s\r\n", temp);
    
    for(i = 0; i < strlen(temp) + 1; i++){
        printf("%x ", temp[i]);
    }

    free(temp);

    return 0;
}

```

*実行結果*

```
gcc -Wall test.c

./a.exe
Original Message
4f 72 69 67 69 6e 61 6c 20 4d 65 73 73 61 67 65 0

```

## 追記(strdup()版)

コメントいただいたのを追加！
strdupのが楽ですね。
free()するのに、<stdlib.h>が必要なのがなんか嫌ですが。。

```c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char OrgMessage[] = "Original Message";
    char *temp = NULL;
    int i;

    temp = strdup(OrgMessage);
    
    if(temp == NULL){
        printf("failed strdup\r\n");
        exit(EXIT_FAILURE); 
    } else {
        printf("%s\r\n", temp);
        
        for(i = 0; i < strlen(temp) + 1; i++){
            printf("%x ", temp[i]);
        }

        free(temp);
    }
    return 0;
}

```


*実行結果*

```

gcc -Wall test.c

./a.exe
Original Message
4f 72 69 67 69 6e 61 6c 20 4d 65 73 73 61 67 65 0

```

## 追記(strndup()版)

strdup()はstrcpy()と同じ問題があるような感じがしたので、
strndup()版も作成してみました。

```c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char OrgMessage[] = "Original Message";
    char *temp = NULL;
    int i;

    temp = strndup(OrgMessage, (strlen(OrgMessage) + 1));

    if(temp == NULL){
        printf("failed strdup\r\n");
        exit(EXIT_FAILURE); 
    } else {
        printf("%s\r\n", temp);
        
        for(i = 0; i < strlen(temp) + 1; i++){
            printf("%x ", temp[i]);
        }

        free(temp);
    }
    return 0;
}

```

*実行結果*

```

./a.exe
Original Message
4f 72 69 67 69 6e 61 6c 20 4d 65 73 73 61 67 65 0


```

## 追記(strlen()について)

sizeof()と異なり、strlen()は文字数分の*メモリオーバーヘッドが発生する*とコメントをいただきました。

文字数が毎回異なり、sizeを取得し直すようなプログラムを作って、遅くて困った時は、
文字数を固定値にしてしまえばstrlen()分の処理が不要になって早くなるのかなーって感じですかねー？？？

クロックの遅いマイコン等だったら(malloc()とあわせて)検討すると良いかも？？？

現状(私が作っている環境)ではそこまで非力じゃないから気にしなくて良いかな？？


### メモ(プロトタイプ)

```c

#include <string.h>

char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
size_t strlen(const char *s);
  /* 文字列*sの長さを返す。長さに'\0'は含まない。 */

char *strdup(const char *s);
char *strndup(const char *s, size_t n);

```

## 謝辞

ご指摘ありがとうございますm(_ _)m

- shiracamusさん
- fujitanozomuさん
- bsdhackさん

## 変更履歴
| 日付 | 変更箇所 |
|------|---------|
| 2017/03/13 | 新規作成<br />コードに色つけました(^_^)b |
| 2017/03/14 | コメントいただいた内容を反映。(strncpy版) |
| 2017/03/16 | コメントいただいた内容を反映。(strdup版、ついでにstrndup版) |