同じミスを繰り返すのでメモ
Cでよくこんな感じのコードを書く。
そして、Segmentation fault(コアダンプ)と表示されてしばらく悩む(^_^;)
gdbでデバッグ始めて、落ちてる場所特定して、で終われば良いんだけど、そこじゃないところで落ちてるように見えるんで、さらに悩む。
#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;
}
正しくはこっち
#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()を使いましょう。(標準ではありません。)
#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()するのに、が必要なのがなんか嫌ですが。。
#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()版も作成してみました。
#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()とあわせて)検討すると良いかも???
現状(私が作っている環境)ではそこまで非力じゃないから気にしなくて良いかな??
メモ(プロトタイプ)
#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 | 新規作成 コードに色つけました(^_^)b |
2017/03/14 | コメントいただいた内容を反映。(strncpy版) |
2017/03/16 | コメントいただいた内容を反映。(strdup版、ついでにstrndup版) |