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

时间:2016-08-14 03:30:58

标签: c token

我正在尝试对字符串数组进行标记,但是,我的程序会继续打印这些奇怪的字符。我相信它与null终止我的字符串有关。如果这是问题,那么我该怎么做才能解决它?

#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;
}

这是输出的照片。

谢谢

4 个答案:

答案 0 :(得分:2)

你要么搞砸了s的声明(最有可能是你剩下的代码),要么你搞砸了s的声明并在s上调用了strtok(这是一个指针指向char *的数组,包含指向字符串文字的指针,如图所示。)

您似乎确实希望char s[]作为您的声明。这将揭示初始化中几个缺少 几个无关 ','的问题。要将s声明为 array-of-char ,并按逗号分隔值列表进行初始化,您基本上需要

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

如果你的意图是创建一个指针数组到char * (例如char *s[]),那么你必须重做声明和代码的其余部分,因为(1)您没有将字符指针传递给strtok;和(2)strtok修改传递的字符串,调用strtok,同时传递字符串文字只是明显错误 - 并保证 SegFault

如果您有任何问题,请与我们联系。

作为指向char *的指针数组

如果您需要在s中找到每个字符串的卑鄙平均值,请从评论中选择s一个指向char *的指针数组。正如评论中所述,您无法初始化char *s[]以包含{ "stuff", "morestuff", ... },因为"stuff""morestuff"字符串文字,并且在大多数情况下都会创建在只读内存中。由于strtok修改了原始字符串,因此您将尝试修改只读内存,其中9次中有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来完成代码。 e.g。

#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

仔细看看,如果您有任何其他问题,请告诉我。

答案 1 :(得分:1)

r获取一个指向字符数组的指针(我在这里称之为“字符串”),但是你传递的是字符串数组

此外,bool buttonLocked; System.Timers.Timer t = new System.Timers.Timer(1000); //however many milliseconds t.Elapsed += new EventHandler(resetFlag); private void button_clicked(object sender, EventArgs e){ if(!buttonLocked){ // Handle Click buttonLocked= true; t.Enabled = true; } } private void resetFlag(){ buttonLocked = false; t.Enabled = false; } 通过使用空字符替换分隔符来修改您传入的字符串。

传递给strtok()的字符串数组包含指向数组中各个字符串的指针。因此,乱码显示是这些指针显示为字符串的结果。此外,当strtok()修改您提供的“字符串”时,这可能会导致各种内存损坏。

答案 2 :(得分:1)

试图预测BLUEPIXY与Nuchy的解决方案存在的两个问题,下面的代码将常量字符串复制到用户分配的内存中,以便在Unix上修改它们没有BUS错误。

以下使用较新的,可重入的strsep()代替strtok()

", ",如果传递给strsep(),与原始代码不同,不会破坏和删除逗号和空格的组合,它会在两者处中断。但只是使用","会在数据上留下不需要的空间,我会单独删除。

最后,我重新格式化了数据以清楚地表明有四个输入字符串,而不是三个,并计算字符串数而不是硬编码计数:

#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;
}

答案 3 :(得分:0)

您需要单独标记每个字符串 - 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;
}

这当然要求您提前知道数组的大小。