PaizaでC言語使ってて困ること
みなさんこんにちは。
Paizaなんかではよくデータの長さを標準入力で与えられて,
それにもとづいてデータ列が標準入力から
入ってくるなんてことがあります。
データの長さが不定なので,sscanfに引数を与えようにもいくつ用意したらいいかわからない。
そういうこともあると思います。
そこで本記事で紹介するような関数を実装しました。
実装した関数
#include <stdio.h>
#include <string.h>
void splitStringToInt(char* src,int* array,int num)
{
int i = 0;
char* head = src;
char* tail;
while (i < num){
if ((tail = strstr(head," ")) != NULL){
*tail = '\0';
sscanf(head,"%d",&(array[i++]));
head = tail + 1;
}
else {
sscanf(head,"%d\n",&(array[i++]));
}
}
}
軽い解説
データ列は最後のデータ以外は空白で区切られているということで上記のような実装を行いました。
また配列のオーバーランを防ぐため念の為個数で管理するようにしています。
インクリメント演算子が後置になっているので,代入後にカウントアップすることにも注意してください。
追記(2021/08/09 14:24)
@fujitanozomuさんから次のような実装のほうがシンプルなのではとのご指摘がございましたので紹介いたします。
void splitStringToInt(char* src,int* array,int num)
{
for (int i = 0; i < num; i++) {
char* token = strtok(src, " ");
if (token == NULL || sscanf(token, "%d", &array[i]) != 1) {
array[i] = /*error*/INT_MIN;
}
src = NULL;
}
}
僭越ながら解説させていただきますと,Cの標準ライブラリにあるstrtok関数を用いて,区切り文字によって文字列をトークンに分割する処理を行うことで
私の実装で行っていた文字列のポインタ管理を,ライブラリに任せることができるようになっています。
その結果としてコードの信頼性が上がり,またシンプルになっていることが特徴です。
またwhile文をfor文に変更することでループがシンプルになっていることも特徴です。
上記2つの結果としてコードが短くなり,保守性が向上しています。
さらにもう一つのコードもご提案いただきましたので紹介いたします。
int splitStringToInt(char* src, int* array, int num)
{
int count = 0;
for (int i = 0; i < num; i++) {
char* token = strtok(src, " ");
if (token != NULL && sscanf(token, "%d", &array[i]) == 1) {
count++;
} else {
array[i] = /*error*/INT_MIN;
}
src = NULL;
}
return count;
}
こちらはトークンの個数を返り値として与えるようにさらに変更したものとなります。
@fujitanozomuさん,コメントで良い実装をご提案いただきありがとうございます。