2016-08-14 58 views
-1

我试图来标记字符串数组,但是,我的程序保留打印这些奇怪的字符。我相信它与null结束我的字符串有关。如果那是问题,那么我能做些什么来解决它?String符号化性格怪异输出

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

这里是输出的照片。

谢谢

+0

看到警告。修复如[this](http://ideone.com/f320eY) – BLUEPIXY

回答

2

你要么搞砸了你的s声明(最有可能给予你剩余的代码),或者你已经搞砸了你如何声明s并调用strtok的上s(这是一个数组的指针,以-char *包含指向字符串文字,书面)。

看来你真的想char s[]为你的宣言。这会暴露几个缺失的问题几个无关',' 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 

如果你的目的是为了创造一个阵列的-pointers到的char *(如char *s[]),则必须返工的声明和你的代码的其余部分,因为:(1)你是不是传递一个字符指针strtok;和(2)strtok修改它传递的字符串拨打电话strtok,同时传递字符串文字只是明显错误 - 并保证SegFault

让我知道如果您有任何问题。


作为一个数组的指针到字符*

从你的评论,如果你需要找到意味着每个个体线的平均s ,那么s必须是指针数组指针*。正如评论所解释的,你不能初始化char *s[]包含{ "stuff", "morestuff", ... }因为"stuff""morestuff"字符串文字,在大多数情况下,将在创建只读内存。由于strtok修改原始字符串,你会试图修改只读内存,其中9次中有10个结果中友好分段错误(不好)。

但是,您可以简单地创建单独的字符串作为字符数组然后创建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); 
     } 

在这两种情况下,你的sum和每个字符串的average将类似于以下内容:

$ ./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 

看一下,然后告诉我知道,如果你有任何问题。

+0

这工作得很好,它打印就像它应该。我试图编写一个程序,然后将这些标记化的字符串转换为双精度,然后找到每行的平均值。在我的教师解决方案中,他使用char * = s [..]并用逗号分隔数组中的每个字符串;所以这就是为什么我认为我也需要这样做。我仍然不确定他为什么这么做,或者他是如何做到的。谢谢你的帮助! :) – CheetahBongos

+1

如果您需要每个*行*的均值,并且您认为*行*是''“12,34,56,78”',那么你*将*需要'char * s []',这样你就可以将每一行传递给'strtok'或'strsep'。然而,你不能以你最初的方式声明's',因为在*'{“stuff”,“morestuff”,...}中包含*的“stuff”是*字符串文字*创建为*只读* “.rodata”部分的内存(Linux)。由于'strtok'和'strsep'修改了原始字符串,因此将只读字符串传递给'strtok'会导致*段错误*或('segfault')。我会工作的另一种选择,也请参阅* cdlane's *答案。 –

+0

你的编辑帮了很多!感谢您的帮助和时间。 – CheetahBongos

1

strtok()需要一个指向一个字符数组(我称之为一个“串”在这里),但你传递一个字符串数组的。

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

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

0

您需要单独tokenise每个字符串 - ()函数接受一个指向字符作为它的第一个参数的strtok:

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

这当然 - 要求您事先知道数组的大小。

+0

这有两个问题。 – BLUEPIXY

+1

为什么4在's'中有3个条目?另外,你正在修改字符串文字,如果你转移到一个基于Unix的机器,文字存在于只读存储器中,这肯定会让你的代码头疼。 –

+0

s中有4个独立的字符串。你是对的,虽然 - strtok修改输入字符串,这会导致问题。 – Nunchy

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; 
} 
+0

哈!你甚至可以通过使用'strsep'来保护空场,这是一份好工作。然而,如果我是一个投注的人,(我不是),我会愿意投注,由于处理* char指针数组需要额外的复杂性,所以OP可能有他的问题's'的声明,而不是他的代码的其余部分。但这只是一个有教养的猜测':)' –

+0

@ DavidC.Rankin,我想我应该采取那个赌注! – cdlane

+0

是的,我会挖掘我的口袋来支付':)'(这是一个很好的例子,为什么我不是一个包含我无法控制的不确定性的东西的投注人)。 –