1

はい、私も初心者です。そして、私はかなり長い間この問題を抱えてきました。strtok を使用して文字列を分割しようとしていますが、うまくいきません。マンページとオンラインの例を見てきましたが、まだ答えがありません。

以下のコードでは、このサイトで回答として提供されているサンプル コードを使用しようとしました。元の while ループは次のとおりです。

    char str[] = "hello world how are you?\n";
    char *res;

    res = strtok(str, " \n");
    puts(res);
    while (res != NULL)
    {
        res = strtok(NULL, " \n");
        if(res!=NULL)
            puts(res);
    }

ただし、str をデータに変更し、それぞれの区切り文字 (&=) を変更すると、セグメンテーション フォールトになります。これを修正するにはどうすればよいですか? コードのどこが間違っていますか? これが完全なコードです。

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

int main()
{
    char *data;

    data = "integer1=1&integer2=2&integer3=3&integer4=4";
    puts(data);

    char str[] = "hello world how are you?\n";
    char *res;

    res = strtok(data, "=&");
    puts(res);
    while (res != NULL)
    {
        res = strtok(NULL, "=&");
        if(res!=NULL)
            puts(res);
    }

    return 0;
}

ちなみにstrtok_r関数も動かない。

4

3 に答える 3

3

これ:

char str[] = "hello world how are you?\n";

配列を作成し、文字列リテラルの内容で初期化します。ただし、これは次のとおりです。

char *data;

data = "integer1=1&integer2=2&integer3=3&integer4=4";

文字列リテラルの最初の文字へのポインターであると宣言dataします。これはもちろん読み取り専用であるため、strtok()変更しようとすると失敗します (未定義の動作を呼び出します)。


ノート:

  1. そのため、文字列リテラルへのポインターを として宣言しconst char *明示的に として宣言しない char *のはそのためです。そうすれば、私はあなたを見つけて const 修飾します。

  2. 配列はポインターではありません。

于 2013-07-05T06:39:01.533 に答える
2

観察している動作は、 com.lang.c FAQの質問 1.32 で説明できます。

これらの初期化の違いは何ですか?

char a[] = "string literal";
char *p  = "string literal";

p[i] に新しい値を割り当てようとすると、プログラムがクラッシュします。

答えは次のとおりです。

文字列リテラル (C ソースの二重引用符で囲まれた文字列の正式な用語) は、2 つのわずかに異なる方法で使用できます。

  1. char a[] の宣言のように、char の配列の初期化子として、その配列内の文字の初期値 (および、必要に応じてそのサイズ) を指定します。
  2. それ以外の場所では、名前のない文字の静的配列に変わり、この名前のない配列は読み取り専用メモリに格納される可能性があるため、必ずしも変更することはできません。式のコンテキストでは、配列は通常どおり (セクション 6 を参照) すぐにポインターに変換されるため、2 番目の宣言は p を初期化し、名前のない配列の最初の要素を指すようにします。
于 2013-07-05T06:45:32.510 に答える
0

strtokメモリブロックを壊します。また、リテラル文字列は変更できません。strtokeしたがって、両方に使用することはできません。これを試して:

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

int main(){
    char *data;

    data = "integer1=1&integer2=2&integer3=3&integer4=4";
    char *cur, *res;

    cur = data;
    res = strpbrk(cur, "=&");
    while (res != NULL)
    {
        fwrite(cur, 1, res-cur, stdout);
        fputc('\n', stdout);

        cur = res + 1;
        res = strpbrk(cur, "=&");
    }
    fputs(cur, stdout);

    return 0;
}

これはメモリブロックを変更しません。

于 2013-07-05T06:54:44.623 に答える