🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

1176閲覧

C言語のstrncpy関数について

Courange

総合スコア17

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/11/09 04:45

前提

AOJのこの問題を解いています。

該当のソースコード・試したこと

問題を解こうと9b.cを書いたのですがstrncpyでcardcpy1に代入するときにうまく動作しない(指定した文字数以上を代入してしまう)ので、何が問題があるのかを知るために9btest.cを書いたのですが結局よくわかりませんでした。

9b.c

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4int main (){ 5 char card[201]; 6 char cardcpy1[201],cardcpy2[201]; 7 int m,h,i,j,substr,wordcount,lenght; 8 while(1){ 9 scanf("%s",card); 10 if(card[0] =='-')break; 11 scanf("%d",&m); 12 for(i = 0,lenght = strlen(card);i < m;i++){ 13 scanf("%d",&h);//hは対象文字数 14 substr = h;//substrには対象文字以外の先頭の 15 wordcount = lenght - h; 16 17 /*cardcpy1に対象文字を代入する*/ 18 strncpy(cardcpy1,&card[0],h); 19 printf("cardcpy1:%s\n");//デバッグ 20 /*cardcpy2に対象文字以外を代入する*/ 21 strncpy(cardcpy2,&card[substr],wordcount); 22 printf("cardcpy2:%s\n");//デバッグ 23 24 /*cardcpy2にシャッフルの結果を代入*/ 25 strcat(cardcpy2,cardcpy1); 26 printf("現在のシャッフル:%s\n",cardcpy2);//デバッグ 27 strcpy(card,cardcpy2); 28 } 29 printf("%s\n",card); 30 } 31return 0; 32} 33

input

1aabc 23 31 42 51

output

1aabc 23 31 4cardcpy1:aabc 5cardcpy2:abc 6現在のシャッフル:abcaa 72 8cardcpy1:abcaa 9cardcpy2:caa 10現在のシャッフル:ccaaa 111 12cardcpy1:ccaaa 13cardcpy2:caaa 14現在のシャッフル:caaac 15caaac

9btest.c

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4int main (){ 5 char card[201]; 6 char cardcpy1[201],cardcpy2[201]; 7 int m,h,i,j,substr,wordcount,lenght; 8 9 scanf("%s",card); 10 strncpy(cardcpy1,&card[0],1); 11 printf("cardcpy1:%s\n");//デバッグ 12 printf("%s\n",card); 13return 0; 14} 15

input

1aabc

output

1cardcpy1:aabc//本当はここでcardcpy1:aとなってほしい 2aabc

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

LouiS0616

2019/11/09 05:00

9btest.cは警告を山ほど吐きますが、確認されましたか。
yokotatsu

2019/11/09 07:22 編集

これは、どういう問題なのでしょうか。 入力のaabc及び3,1,2,1とはなんでしょうか。 どのようなoutputがでれば良いのでしょうか。 又、strncpy関数を使用することが必須なのですか。
Courange

2019/11/09 15:13

改めてみるとかなりひどいコードというのは理解してはいるのですが、警告やエラーが一切出ていないのですよね・・・
LouiS0616

2019/11/09 15:15

どのようにコンパイルしていますか?
guest

回答2

0

ベストアンサー

全てのコードは見ていませんが、、、

まず、

strncpy(cardcpy1,&card[0],h);

h バイトのコピーとなります。 最後に、'\0' は付けません。C 言語での文字列は、最後が '\0' となる規則なので、コピーした文字列 + ゴミ となる事があります。

printf("cardcpy1:%s\n");//デバッグ

cardcpy1 の文字列を出力したいのでは無いかと推測しますが、期待する文字列は出力されません。 下記のようにすべきでしょう。 (cardcpy1 を出力する場合)
printf("cardcpy1:%s\n", cardcpy1);//デバッグ
%sは、次の引数を文字列と見なし、出力しますが、 次の引数が無いので、動作は不明となります。(ゴミが出力される?)

投稿2019/11/09 04:58

pepperleaf

総合スコア6385

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2019/11/09 05:28

> h バイトのコピーとなります。 最後に、'\0' は付けません。 少し語弊があるかもしれません。strncpyの場合、コピー元文字列の長さより"多く"第3引数がセットされているならば、'\0'は付けられます。 #include <stdio.h> #include <string.h> #include <stdlib.h> int main(void) { char s[10]; memset(s,'*', sizeof(s)); s[9] = '\0'; strncpy(s, "12345", sizeof(s)); printf("%s\n", s); memset(s, '*', sizeof(s)); s[9] = '\0'; strncpy(s, "12345", 5); printf("%s\n", s); return 0; } 実行例です。 $ gcc -Wall t1.c -o t1.exe;./t1.exe 12345 12345****
pepperleaf

2019/11/09 11:53 編集

> コピー元文字列の長さより"多く"第3引数がセットされているならば、'\0'は付けられます。 失礼、ちょっと手抜きでした。 コピー元の文字列より短い文字数(バイト数)が指定された場合、自動で、'\0'が付けられないが正しいですね。
Courange

2019/11/10 04:48

正直理解にかなり時間がかかりました・・・ ですが、以下のコードでなんとか正解することができました! #include <stdio.h> #include <stdlib.h> #include <string.h> int main (){ char card[201]; char cardcpy1[201],cardcpy2[201]; int m,h,i,j,substr,wordcount,lenght; while(1){ scanf("%s",card); if(card[0] =='-')break; scanf("%d",&m); for(i = 0,lenght = strlen(card);i < m;i++){ scanf("%d",&h);//hは対象文字数 substr = h;//substrには対象文字以外の先頭の wordcount = lenght - h; /*cardcpy1に対象文字を代入する*/ strncpy(cardcpy1,card,h); cardcpy1[h]='\0'; //printf("cardcpy1:%s\n",cardcpy1);//デバッグ /*cardcpy2に対象文字以外を代入する*/ strncpy(cardcpy2,&card[h],wordcount); cardcpy2[wordcount]='\0'; //printf("cardcpy2:%s\n",cardcpy2);//デバッグ /*cardcpy2にシャッフルの結果を代入*/ strcat(cardcpy2,cardcpy1); memset(card,0,sizeof(card)); card[200]='\0'; strcpy(card,cardcpy2); //printf("現在のシャッフル:%s\n",card);//デバッグ } printf("%s\n",card); } return 0; }
Courange

2019/11/10 04:49

(インデント全くないのはご了承ください・・・)
rubato6809

2019/11/10 10:48 編集

期待どおりの結果が得られて結構でした。でもムダが多い。改良の余地があります。これで完成と思わないほうが良いです。今の時点では3点アドバイスできます。 (1) strncpy() でなく strcpy() で実現可能 (2) 配列は2本あれば十分 (3) memset() と card[200] = '\0'; および cardcpy2[wordcount]='\0'; は不要
Courange

2019/11/10 13:20

アドバイスありがとうございます。なるべく無駄を減らせるよう頑張りたいと思います。
guest

0

9b.cを修正しました。いかのようにしてください。
strncpy関数は実にやっかいな関数です。コピー先の終わりに終端文字('\0')を付加されるときと、付加されないときがあるのです。
今回のケースでは終端文字が付加されないので、意図的に付加してあげる必要があります。(//追加のコメントがある文です。)
それと、デバッグのために、cardcpy1,2を印字していますが、誤っているために、正しく修正しておきました。(//修正のコメントがある文です。)
strncpyで終端文字('\0')が付加されるかされないかは、説明を精読し、十分理解した後、使ってください。
(strncmp,strncatも同様にやっかいな関数ですので、それらを使用するときも気を付けてください)

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4int main() 5{ 6 char card[201]; 7 char cardcpy1[201], cardcpy2[201]; 8 int m, h, i, j, substr, wordcount, lenght; 9 while (1) { 10 scanf("%s", card); 11 if (card[0] == '-') 12 break; 13 scanf("%d", &m); 14 for (i = 0, lenght = strlen(card); i < m; i++) { 15 scanf("%d", &h); //hは対象文字数 16 substr = h; //substrには対象文字以外の先頭の 17 wordcount = lenght - h; 18 /*cardcpy1に対象文字を代入する */ 19 strncpy(cardcpy1, &card[0], h); 20 cardcpy1[h]='\0'; //追加 終端文字設定 21 printf("cardcpy1:%s\n",cardcpy1); //修正 デバッグ正しく印字 22 /*cardcpy2に対象文字以外を代入する */ 23 strncpy(cardcpy2, &card[substr], wordcount); 24 cardcpy2[wordcount]='\0'; //追加 終端文字設定 25 printf("cardcpy2:%s\n",cardcpy2); //修正 デバッグ正しく印字 26 27 /*cardcpy2にシャッフルの結果を代入 */ 28 strcat(cardcpy2, cardcpy1); 29 printf("現在のシャッフル:%s\n", cardcpy2); //デバッグ 30 strcpy(card, cardcpy2); 31 } 32 printf("%s\n", card); 33 } 34 return 0; 35}

投稿2019/11/10 03:40

yokotatsu

総合スコア92

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問