字符串标记化奇怪字符输出

String tokenization strange character output

我正在尝试标记一个字符串数组,但是,我的程序一直在打印这些奇怪的字符。我相信这与以空值终止我的字符串有关。如果这是问题所在,那么我该怎么做才能解决它?

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

int main(void)
{
    char* s[] = { "12, 34, 56, 78", "82.16, 41.296",
                  "2, -3, 5, -7, 11, -13, 17, -19",
                  "9.00009, 90.0009, 900.009, 9000.09, 90000.9" };

    char *token = strtok(s, ", ");

    while (token != NULL) {
        printf("%s\n", token);
        token = strtok(NULL, ", ");
    }
    return 0;
}

这是输出的照片。

谢谢

strtok() 接受一个指向字符数组的指针(我在这里称之为 "string"),但是你传递给它的是一个 字符串数组 .

此外,strtok() 通过用空字符替换定界符来修改您传入的字符串。

您要传递给 strtok() 的字符串数组由指向数组中各个字符串的指针组成。所以乱码显示是这些指针被显示为字符串的结果。此外,当 strtok() 修改您提供的 "string" 时,这可能会导致各种内存损坏。

您需要分别标记每个字符串 - strtok() 函数接受一个指向 char 的指针作为其第一个参数:

char *strtok(char * str, const char * delim);

类似于:

#define _CRT_SECURE_NO_WARNINGS

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

int main(void)
{
    char* s[] = { "12, 34, 56, 78", "82.16, 41.296",
                  "2, -3, 5, -7, 11, -13, 17, -19",
                  "9.00009, 90.0009, 900.009, 9000.09, 90000.9" };
    int sNo = 0;

    while (sNo < 4) {
        char *token = strtok(s[sNo++], ", ");

        while (token != NULL) {
            printf("%s\n", token);
            token = strtok(NULL, ", ");
        }
    }

    return 0;
}

当然,这需要您事先知道数组的大小。

您要么弄乱了 s 的声明(很可能考虑到您的其余代码),要么弄乱了声明 s 和在 [=17= 上调用 strtok 的方式](这是一个字符指针数组*,包含指向字符串文字的指针。)

看来您确实想要 char s[] 作为您的声明。这将揭示初始化中几个 缺失 几个 无关的 ',' 的问题。要将 s 声明为已初始化的 字符数组 并保存 逗号分隔值 列表,您实际上需要

char s[] = { "12, 34, 56, 78, ....,  9000.09, 90000.9" };

没有要求您在初始化时只有一组引号 (".."),但是您要从字符串中标记化的每个值都必须有一个 逗号 之后(最后一个值除外)。您可以按如下方式声明和初始化 s

char s[] = { "12, 34, 56, 78," "82.16, 41.296,"
              "2, -3, 5, -7, 11, -13, 17, -19,"
              "9.00009, 90.0009, 900.009, 9000.09, 90000.9" };

您的代码的其余部分在这种情况下工作正常,产生以下输出:

$ ./bin/strtok_arr
12
34
56
78
82.16
41.296
2
-3
5
-7
11
-13
17
-19
9.00009
90.0009
900.009
9000.09
90000.9

如果您的意图是创建一个 array-of-pointers-to-char*(例如 char *s[]),那么您必须修改声明和其余部分您的代码,因为 (1) 您没有将字符指针传递给 strtok;和 (2) strtok 修改它传递给 strtok 的字符串,同时传递 字符串文字 完全错误 - 并保证 SegFault.

如果您有任何问题,请告诉我。


作为字符指针数组*

根据您的评论,如果您需要找到 s 中每个单独字符串的 meanaverage , 那么 s 必须是 一个字符指针数组 *。如评论中所述,您不能将 char *s[] 初始化为包含 { "stuff", "morestuff", ... } 因为 "stuff""morestuff" 字符串文字 并且在大多数情况下将在只读内存中创建。由于 strtok 修改了原始字符串,您将尝试修改 只读 内存,10 次中有 9 次会导致友好的 分段错误(不好)。

然而,您可以简单地将单个字符串创建为 字符数组 ,然后从字符数组创建 s,例如:

    char s1[] = "12, 34, 56, 78",
         s2[] = "82.16, 41.296",
         s3[] = "2, -3, 5, -7, 11, -13, 17, -19",
         s4[] = "9.00009, 90.0009, 900.009, 9000.09, 90000.9",
         *s[] = { s1, s2, s3, s4 };

然后,您可以通过使用 strtok 标记每个字符串并将每个值转换为 double,同时收集每个字符串的 sumaverage 来完成您的代码。例如

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

int main (void)
{
    char s1[] = "12, 34, 56, 78",
         s2[] = "82.16, 41.296",
         s3[] = "2, -3, 5, -7, 11, -13, 17, -19",
         s4[] = "9.00009, 90.0009, 900.009, 9000.09, 90000.9",
         *s[] = { s1, s2, s3, s4 };
    size_t i, idx = 0, n = sizeof s/sizeof *s;
    double avg[n];

    for (i = 0; i < n; i++) {

        double sum = 0.0;
        size_t nval = 0;
        char *token = strtok (s[i], ", ");

        while (token != NULL) {
            sum += strtod (token, NULL);
            nval++;
            printf ("  %8s, sum : %9.2lf\n", token, sum);
            token = strtok (NULL, ", ");
        }
        printf ("----------------------------\n");
        printf ("        average : %9.2lf\n\n", (avg[idx++] = sum/nval));
    }

    return 0;
}

我可能会将标记化循环重写为 for 循环,以在循环定义本身中包含 nval 增量,例如

        for (; token; token = strtok (NULL, ", "), nval++) {
            sum += strtod (token, NULL);
            printf ("  %8s, sum : %9.2lf\n", token, sum);
        }

无论哪种情况,每个字符串的 sumaverage 将如下所示:

$  ./bin/strtok_arr1
        12, sum :     12.00
        34, sum :     46.00
        56, sum :    102.00
        78, sum :    180.00
----------------------------
        average :     45.00

     82.16, sum :     82.16
    41.296, sum :    123.46
----------------------------
        average :     61.73

         2, sum :      2.00
        -3, sum :     -1.00
         5, sum :      4.00
        -7, sum :     -3.00
        11, sum :      8.00
       -13, sum :     -5.00
        17, sum :     12.00
       -19, sum :     -7.00
----------------------------
        average :     -0.88

   9.00009, sum :      9.00
   90.0009, sum :     99.00
   900.009, sum :    999.01
   9000.09, sum :   9999.10
   90000.9, sum : 100000.00
----------------------------
        average :  20000.00

仔细阅读,如果您还有其他问题,请告诉我。

试图预测 BLUEPIXY 在 Nuchy 的解决方案中存在的两个问题,以下代码将常量字符串复制到用户分配的内存中,以便可以在 Unix 上修改它们而不会出现 BUS ERROR。

以下使用较新的可重入 strsep() 而不是 strtok()

", ",如果传递给 strsep(),与原始代码不同,它不会在逗号和 space 的组合处中断,它会在两个处中断.但仅使用 "," 会在数据上留下不需要的 space,我将其单独删除。

最后,我重新格式化数据以明确输入字符串是四个,而不是三个,并计算字符串的数量而不是硬编码计数:

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

#define BUFFER_SIZE (1024)

int main(int argc, char *argv[]) {

    char strings[][BUFFER_SIZE] = {
        "12, 34, 56, 78",
        "82.16, 41.296",
        "2, -3, 5, -7, 11, -13, 17, -19",
        "9.00009, 90.0009, 900.009, 9000.09, 90000.9"
    };

    size_t limit = sizeof(strings) / BUFFER_SIZE;

    for (size_t i = 0; i < limit; i++) {
        char *token, *string = strings[i];

        while ((token = strsep(&string, ",")) != NULL) {
            while (isspace(*token)) {
                token++;
            }
            printf("%s\n", token);
        }
    }

    return 0;
}