2016-08-14 53 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

是的,我會挖掘我的口袋來支付':)'(這是一個很好的例子,爲什麼我不是一個包含我無法控制的不確定性的東西的投注人)。 –