字符串标记化奇怪字符输出
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
中每个单独字符串的 mean 或 average , 那么 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
,同时收集每个字符串的 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
仔细阅读,如果您还有其他问题,请告诉我。
试图预测 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;
}
我正在尝试标记一个字符串数组,但是,我的程序一直在打印这些奇怪的字符。我相信这与以空值终止我的字符串有关。如果这是问题所在,那么我该怎么做才能解决它?
#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
中每个单独字符串的 mean 或 average , 那么 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
,同时收集每个字符串的 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
仔细阅读,如果您还有其他问题,请告诉我。
试图预测 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;
}