2016-08-14 3 views
-1

Я пытаюсь tokenize массив строк, однако моя программа продолжает печатать эти странные символы. Я считаю, что это связано с нулевым завершением моей строки. Если это проблема, то что я могу сделать, чтобы исправить это?String tokenization странный вывод символов

#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

см предупреждение. исправить как [этот] (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-to-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 }; 

Вы можете закончить ваш код tokenizing каждой из строк с strtok и преобразование каждого значения в double при сборе sum и average каждого. например

#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 '' содержал * внутри * '{" stuff "," morestuff ", ...}' are * string литералы *, созданные в * только для чтения * память раздела '.rodata' (Linux). Поскольку 'strtok' и' strsep' изменяют исходную строку, передача строки только для чтения в 'strtok' приведет к * segmentation fault * или (' segfault'). Я буду использовать альтернативу, также см. Ответ * cdlane *. –

+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

это есть 2 проблема. – BLUEPIXY

+1

Почему 4, когда в '' 'есть 3 записи? Кроме того, вы изменяете строковые литералы, которые, безусловно, будут давать головные боли в коде, если вы когда-нибудь перейдете на компьютер на основе Unix, где литералы живут в памяти только для чтения. –

+0

Есть 4 отдельных строки в s. вы правы, хотя - strtok изменяет входную строку, и это вызовет проблемы. – Nunchy

1

Попытка предвидеть две проблемы, которые BLUEPIXY имеет с решением Nuchy, следующий код копирует постоянные строки в выделенную пользователем память, чтобы они могли быть изменены без шинной ошибки в Unix.

Нижеследующий использует новый, реентеративный strsep() вместо strtok().

", ", если он передан в strsep(), в отличие от исходного кода, не разбивает и не удаляет комбинацию запятой и пробела, он ломается на обоих. Но просто используя "," оставляет ненужное место на данных, которые я удаляю отдельно.

Наконец, я reformated данных, чтобы понять, что есть четыре входных строк, а не три, и вычислить количество строк вместо жесткого кодирования графа:

#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

Hah! Вы даже защищаете от пустого поля, используя 'strsep', хорошую работу. Однако, если бы я был игроком по ставкам (которого я не буду), я готов согласиться на то, что с учетом дополнительной сложности, необходимой для обработки массива указателей на char \ **, у ОП, вероятно, есть свои проблемы в декларация '' ', а не в остальной части его кода. Но это всего лишь образованное предположение ':)' –

+0

@ DavidC.Rankin, я думаю, я должен был принять эту ставку! – cdlane

+0

Да, я буду копать в карманах, чтобы заплатить ':)' (это яркий пример того, почему я не ставлю человека в вещах, содержащих неопределенность, которую я не могу контролировать). –

Смежные вопросы