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

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

詳細はこちら
C

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

Q&A

解決済

2回答

1267閲覧

C言語による以下の記述の何がまちがっているのかを教えてください

hedge14

総合スコア2

C

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

0グッド

0クリップ

投稿2020/11/27 17:41

C言語による以下の記述の何がまちがっているのかを教えてください。お願いします。

以下の問題を解くために記述したものです。
,で区切られた数値を降順にしてくっつけるプログラムです。

シャープ入れると文字が大きくなったのでincludeから始まっていますが、じっさいのプログラムにはシャープが入っています。


下にある配列の中身を大きい順に並べ替えてくっつけてください。
例:もし配列{1,5,3,2}っていう配列があったら、大きい順に並べ替えると{5,3,2,1}となります。なので、答えは{5321}となります。

[15,1,93,52,66,31,87,0,42,77,46,24,99,10,19,36,27,4,58,76,2,81,50,102,33,94,20,14,80,82,49,41,12,143,121,7,111,100,60,55,108,34,150,103,109,130,25,54,57,159,136,110,3,167,119,72,18,151,105,171,160,144,85,201,193,188,190,146,210,211,63,207]


include<stdio.h>

int main(){
int cap = 200;
unsigned char a[cap], b[cap];
int c[cap], tmp;
int s, t, u, i, j, x;

printf("値を入力してください\n");
scanf("%s", &a);

t = 0;
u = 1;

//,を取り除き数値だけをbに格納する。また、elseで全部で何個あるかを記録する。
for ( s = 0;s < cap; ++s) {
if ( a[s] != ',' ) {
b[t] = a[s];
++t;
}else{
u =u+1;
}
//bをint型へ変換する。また、そのときcへ入れる。
for(x=0;x < cap;++x){
c[x] = (int)b[x];
}
//降順ソートする。
for (i=0; i<u; ++i){
for(j=i+1; j<total; ++j){
if(c[i]<c[j]){
tmp = c[i];
c[i] = c[j];
c[j] = tmp;
}
}
}

printf("降順ソートした数値\n");
for(i=0; i<u; i++){
printf("%d\n",c[i]);
}
return 0;
}

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

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

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

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

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

kairi003

2020/11/27 18:12

コードはコードブロック(``` ~ ```) で囲んでください。質問の編集時に「<code>」を押せば入力できます。言語名はcです。 あとどんなエラーが出たのか、何ができないのかを示してください。
hedge14

2020/11/28 03:50

エラーは、コンパイルしたexeを開くと落ちます。
guest

回答2

0

ベストアンサー

まず大きな勘違いとして、文字列と数字の変換があります。

c

1 //bをint型へ変換する。また、そのときcへ入れる。 2 for (x = 0; x < cap; ++x) { 3 c[x] = (int)b[x]; 4 }

という部分が見られますが、これがおかしいことを理解してください。

例えば1という文字があったとき、c[x] = (int)b[x];というのはその文字コードc[x]に入れていることになります。ASCIIで考えるなら0x31ですね。これは本当に望む変換ですか?違いますよね?

さらにもう一つ大きな誤りがあります。

c

1 //,を取り除き数値だけをbに格納する。また、elseで全部で何個あるかを記録する。 2 for (s = 0; s < cap; ++s) { 3 if (a[s] != ',') { 4 b[t] = a[s]; 5 ++t; 6 } 7 else { 8 u = u + 1; 9 } 10 }

区切り文字,を識別しようとしている点は正しいのですが、その区切り文字が何文字目にあったのか記録されていません。例えば123,41という入力に対して、12341に切り分けてこれを数値に変換しなければならないわけですが、これでは困ってしまいます。

さて、ところで文字列を数値に変換するにはstrtol関数を使うのでした。じつはstrtol関数を使うといちいち区切り文字の位置を記録したりする必要はないのです。

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <errno.h> 4#ifndef COUNFOF 5# define COUNFOF(arr) (sizeof(arr) / sizeof(*arr)) 6#endif 7int main(void) 8{ 9 char buf[512]; 10 if (NULL == fgets(buf, COUNFOF(buf), stdin)) { 11 return 1; 12 } 13 long nums[256]; 14 const char* s = buf; 15 char* endptr; 16 size_t i; 17 for (i = 0; i < COUNFOF(nums); ++i) { 18 errno = 0; 19 const long t = strtol(s, &endptr, 10); 20 if (0 != errno || (0 == t && endptr == s)) return 1; 21 nums[i] = t; 22 if (endptr[0] == '\0' || endptr[0] == '\n' || endptr[0] == '\r') { 23 ++i; 24 break; 25 } 26 if (endptr[0] != ',') return 2; 27 s = endptr + 1; 28 } 29 for (size_t j = 0; j != i; ++j) { 30 printf("%ld,", nums[j]); 31 } 32 return 0; 33}

概ね上のようにかけるはずです(ソートは省略)

投稿2020/11/27 18:15

yumetodo

総合スコア5852

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

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

hedge14

2020/11/28 03:41

お答えいただきありがとうございます。 貼っていただいた文をもとにコンパイルしてみたところ、,がのぞかれていませんでした。 1,2,3と入力→1,2,3と表示される。 そこで、,がでたらgotoでforの最後に行き++iをさせて、numに,を入れないようにさせましたが、うまくいきません。原因を教えて下さい。 ''' #include <stdio.h> #include <stdlib.h> #include <errno.h> #ifndef COUNFOF # define COUNFOF(arr) (sizeof(arr) / sizeof(*arr)) #endif int main(void) { char buf[512]; char end; int x = 0; printf("値の入力\n"); if (NULL == fgets(buf, COUNFOF(buf), stdin)) { return 1; } long nums[256]; const char* s = buf; char* endptr; size_t i; for (i = 0; i < COUNFOF(nums); ++i) { errno = 0; const long t = strtol(s, &endptr, 10); if(endptr[x] == ','){ ++x; goto begin; } if (0 != errno || (0 == t && endptr == s)) return 1; nums[i] = t; //終わり if (endptr[x] == '\0' || endptr[x] == '\n') { ++i; break; } begin: //読み取る数字を進める if (endptr[0] != ',') return 2; s = endptr + 1; } for (size_t j = 0; j != i; ++j) { printf("%ld,", nums[j]); } scanf("%s",&end); return 0; } '''
yumetodo

2020/11/28 05:27 編集

落ち着いてください。表示で,が入って見えるのはnumsの値を確認するためにprintfを呼び出す時に"%ld,"としたからで意図した動作です。大事なのはパースした値がきちんとnumsの配列に入っているということで、どう表示されるかに意味はありません。
yumetodo

2020/11/28 05:31

というかerrnoの判定は何を差し置いてもまっさきに行わなければなりません。今回の書き換えではerrnoの値が書き換わってしまうような変更はされていないようですが、好ましい書き換えとは言えません。
hedge14

2020/11/28 10:40

%ldのあとのカンマを見落としていました。すみません。 せっかっくコードを教えていただいたのに、c言語の理解が足らずに四苦八苦していました。もう少し勉強してからまた挑んでみたいと思います。 ありがとうございました。
hedge14

2020/11/29 02:37

わざわざご丁寧にありがとうございます
guest

0

strtol を使うやり方

C

1#include <stdio.h> // puts, scanf, printf, putchar 2#include <stdlib.h> // strtol 3 4int main(void) 5{ 6 const int cap = 200; 7 char a[cap], *p = a, *q; 8 int c[cap], n = 0, tmp; 9 10 puts("値を入力してください"); 11 if (scanf("%s", a) != 1) return 1; 12 13 while (n < cap) { 14 c[n++] = strtol(p, &q, 10); 15 if (q == p) return 2; 16 if (*q != ',') break; 17 p = q + 1; 18 } 19 for (int i = 0; i < n; i++) 20 for (int j = i + 1; j < n; j++) 21 if (c[i] < c[j]) tmp = c[i], c[i] = c[j], c[j] = tmp; 22 23 puts("降順ソートした数値"); 24 for (int i = 0; i < n; i++) printf("%d", c[i]); 25 putchar('\n'); 26 return 0; 27}

sscanf を使うやり方

C

1#include <stdio.h> // puts, scanf, sscanf, printf, putchar 2 3int main(void) 4{ 5 const int cap = 200; 6 char a[cap], *p = a, sep; 7 int c[cap], n = 0, m, k, tmp; 8 9 puts("値を入力してください"); 10 if (scanf("%s", a) != 1) return 1; 11 12 while (n < cap) { 13 k = sscanf(p, "%d%c%n", &c[n++], &sep, &m); 14 if (k < 1) return 2; 15 if (k == 1 || sep != ',') break; 16 p += m; 17 } 18 for (int i = 0; i < n; i++) 19 for (int j = i + 1; j < n; j++) 20 if (c[i] < c[j]) tmp = c[i], c[i] = c[j], c[j] = tmp; 21 22 puts("降順ソートした数値"); 23 for (int i = 0; i < n; i++) printf("%d", c[i]); 24 putchar('\n'); 25 return 0; 26}

投稿2020/11/29 01:59

kazuma-s

総合スコア8224

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

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

hedge14

2020/11/29 13:33

sscanfを使うやり方もあるんですね。sscanfの方が個人的にはわかりやすいです。全体的に関数を知らない、理解できないのが要因のようです。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問