質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

88.57%

英文字列に各文字間にスペースを挿入するプログラム

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 2,142

aiueo12345

score 21

 前提・実現したいこと

C言語を用いて、英文字列に各文字間にスペースを挿入する関数「char *strspace(const char *s)」を含むプログラムを書きたいと思っています。

#include <stdio.h>

char *strspace(const char *s)
{
 ?????
}

int main(void)
{
 char a[9999];
 printf("英文字列を入力してください。\n");
 scanf("%s",a);
 printf("%s\n",strspace(a));
 return 0;
}


例)abcdefg → a b c d e f g

 発生している問題・エラーメッセージ

「const」でポインタsの要素を触ることは禁止されている状態で、関数「char *strspace(const char *s)」をどのように書けばよいのか思いつきません。
どのように考えればよいかご教授ください。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

+3

スペースを入れた結果を格納するバッファのアドレスとそのサイズを引数に取る必要がありますね
元の文字列はいじりません

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/01 21:18

    回答ありがとうございます。
    「バッファ」というものを使わないと書けないプログラムなのですか?
    お恥ずかしいことにまだ「バッファ」について学習していないものでして。。。

    キャンセル

  • 2018/11/01 21:23

    スペースを入れた変換結果を格納する場所が必要になりますよね?
    それをあらかじめ用意しておいて、関数にそれを与えて、それに結果を入れて返すようにします

    バッファといっても、charの配列でいいです

    キャンセル

  • 2018/11/01 21:28

    なるほど、結果を格納することのできる配列を別に準備しておけばいいんですね。
    やってみます。

    キャンセル

  • 2018/11/01 21:32

    そゆことです。
    気をつけなければならないのは、配列のサイズをオーバーしないようにすることです
    文字列の最後の'\0'も含めて、オーバーしないように。

    キャンセル

+3

「const」でポインタsの要素を触ることは禁止されている状態で

sの指す先の文字を変更できないと思ったのであれば、間違いです。 sというポインタ変数に代入できないだけです。

まあ、どっちみち、長さが足りないので、sの指す領域は更新してもしょうがないですが。

引数の文字列長strlen(s)を2倍した値が、結果格納用領域の必要最低限な長さなので、malloc(strlen(s)*2)した領域を使って、そこに、結果文字列を格納してください。

mallocの使い方は分かりますか?

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/02 11:56

    > sというポインタ変数に代入できないだけです。

    重箱の隅をつつくようで申し訳ないですが、逆です。
    const charとchar constは同じ型で
    char * constとconst char*が別の型になります。

    なので、const char* sはs[0]に対して代入できないが、sに対して代入でる型になります。
    https://port70.net/~nsz/c/c11/n1570.html#6.2.5p29

    キャンセル

  • 2018/11/02 12:51 編集

    大変失礼しました。
    長年ちゃんとしたCのプログラムを書いてないのがばれてしまいました。
    自戒のために、誤った解答をしたとわかるようにしておきます。

    キャンセル

  • 2018/11/02 16:07

    私もよくどっちだか忘れてしまいどっちにもconstつける選択をしてしまいます。

    キャンセル

0

strspace 関数中で static な配列を用意した場合、マルチスレッドで問題がでる気がします。
static な配列を使わない、 strspec の引数に結果を格納するエリアとサイズを渡すようにしたものを書いてみました。
扱える文字の長さを 3 にして、境界での動作を試すことを mai() 中で行っています。

a.c

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

#define SRC_BUFF_SIZE (4) // (9999)

const char *strspace(const char *src, char * dest, size_t dest_size) {
  char w[BUFSIZ];
  char *wp = w;
  for (; *src; ) {
    *wp++ = *src++;
    *wp++ = ' ';
  }
  // 最後の ' ' は削除する
  if (w < wp) {wp--;}
  *wp = '\0';

  strncpy(dest, w, dest_size);
  dest[dest_size - 1] = '\0'; // strncpy で '\0' が設定されなかった場合への対処
  return dest;
}

int main(void) {
  char a[SRC_BUFF_SIZE];
  char b[SRC_BUFF_SIZE * 2 - 1];

  strcpy(a, "");
  printf("'%s' -> '%s'\n", a, strspace(a, b, sizeof(b)));
  strcpy(a, "1");
  printf("'%s' -> '%s'\n", a, strspace(a, b, sizeof(b)));
  strcpy(a, "12");
  printf("'%s' -> '%s'\n", a, strspace(a, b, sizeof(b)));
  strcpy(a, "123");
  printf("'%s' -> '%s'\n", a, strspace(a, b, sizeof(b)));
  printf("'%s' -> '%s'\n", a, strspace(a, b, sizeof(b) - 1));
  printf("'%s' -> '%s'\n", a, strspace(a, b, sizeof(b) - 2));

  printf("英文字列を入力してください。(%lu 文字以降は無視されます)\n", sizeof(a) - 1);
  fgets(a, sizeof(a) - 1, stdin);
  printf("'%s' -> '%s'\n", a, strspace(a, b, sizeof(b)));
  return 0;
}

実行例
イメージ説明

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

-1

修正しておきました。
for(i=0;i<strlen(s);i++) ですが、sを変化させているので
strlen(s)の値が、毎回変わってしまいます。
1)これを固定させます。
2)終端は、'\0'を入れないとだめです。(文字列操作の鉄則です)
3)ついでですが、if (2*strlen(s) > sizeof(buff)) return NULL;でreturnしているので
elseにする必要はありません。
for(・・・)から書いても構いません。そのほうがすっきりします。
ここは、動作上は問題ないので、あえて修正しませんでしたが・・・・

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

char *strspace(const char *s)
{
    static char buff[9999*2];
    int i,len;
    if (2*strlen(s) > sizeof(buff)) return NULL;
    else
    {
        len = strlen(s);
        for(i=0;i<len;i++)
        {
            buff[2*i]=*s++;
            buff[2*i+1]=' ';
        }
        buff[2*i-1] = '\0';
        return buff;
    }
}

int main(void)
{
    char a[9999];
    printf("英文字列を入力してください。\n");
    scanf("%s",a);
    printf("%s\n",strspace(a));
    return 0;
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/02 16:38

    strtokはバッファを割り当てるには該当しませんね

    キャンセル

  • 2018/11/02 16:38

    ああ本当ですね。「みな」というのは撤回します。

    キャンセル

  • 2018/11/02 16:46

    再度確認します。
    この実装は気を付けて使わないとバグのもとになるので行儀がよくない、バッファとバッファサイズを与えた方が読みやすくていいというのは私の主観です。
    なぜなら、そのような実装の関数が多く、また他言語から学んだ人は文字列である戻り値が勝手に変わるような仕様にびっくりすると思うからです。
    だから、この実装をまねるなら、しっかりとコメントすべきと主張します。

    キャンセル

-2

内部に十分大きなバッファを確保し、そこへ格納します。
そのバッファに格納できない場合は、NULLを返します。

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

char *strspace(const char *s)
{
    static    char    buff[9999*2];
    if (2*strlen(s) > sizeof(buff)) return NULL;
     //以降 sに空白を付加しながらbuffに文字を格納
     return buff;
}

int main(void)
{
 char a[9999];
 printf("英文字列を入力してください。\n");
 scanf("%s",a);
 printf("%s\n",strspace(a));
 return 0;
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/01 21:27

    回答ありがとうございます。
    このバッファについてよく知らなかったのでこのプログラムを参考に書いてみたいと思います。

    キャンセル

  • 2018/11/02 14:07

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

    char *strspace(const char *s)
    {
    static char buff[9999*2];
    int i;
    if (2*strlen(s) > sizeof(buff)) return NULL;
    else
    {
    for(i=0;i<strlen(s);i++)
    {
    buff[2*i]=*s++;
    buff[2*i+1]=' ';
    }
    return buff;
    }
    }

    int main(void)
    {
    char a[9999];
    printf("英文字列を入力してください。\n");
    scanf("%s",a);
    printf("%s\n",strspace(a));
    return 0;
    }

    これで実行してみたところ、入力した文字のおよそ半分しか出力されませんでした。
    およそというのは、
     1文字入力すると1文字出力され、
     2文字入力すると1文字出力され、
     3文字入力すると2文字出力され、
     4文字入力すると2文字出力され、
     5文字入力すると3文字出力され、
     6文字入力すると3文字出力され、
     7文字入力すると4文字出力されるといった具合です。

    どこを修正すればよいでしょうか?

    キャンセル

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

  • ただいまの回答率 88.57%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る