我想解析一个格式为(6,8)的字符串,我想将6和8存储在不同的变量中。我试图使用" strtok"。但它给了我一个段错误
这是我的代码
int main()
{
char a[80]="(6,8)";
parsing(a);
return 0;
}
int parsing(char* a)
{
char* word;
char temp[80] ;
stpcpy(temp,a);
char* new;
char **newendptr=NULL;
char **newnewendptr=NULL;
int u,v;
word= strtok(temp, "(");
word= strtok(NULL, ",");
u=strtoumax(secword,newendptr,0);
printf("%d\n",u);
new= strtok(NULL, ")");
printf("%s\n",new);
v=strtoumax(new,newnewendptr,0);
printf("%d %d",u,v);
return 1;
}
答案 0 :(得分:2)
仔细阅读strtok()
的规范是值得的。
此代码有效:
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
static int parsing(char *a)
{
char temp[80];
strcpy(temp, a);
printf("temp 0 = %p [[%s]]\n", (void *)temp, temp);
char *word1 = strtok(temp, "(,)");
printf("word 1 = %p [[%s]]\n", (void *)word1, word1 == 0 ? "<nothing>" : word1);
char *word2 = strtok(NULL, "(,)");
printf("word 2 = %p [[%s]]\n", (void *)word2, word2 == 0 ? "<nothing>" : word2);
int u = strtoumax(word1, 0, 0);
int v = strtoumax(word2, 0, 0);
printf("%d %d\n", u, v);
return 1;
}
int main(void)
{
char a[80] = "(6,8)";
parsing(a);
return 0;
}
我机器上的输出是:
temp 0 = 0x7fff54844440 [[(6,8)]]
word 1 = 0x7fff54844441 [[6]]
word 2 = 0x7fff54844443 [[8]]
6 8
问题是,原始strtok()
中"("
的调用会以(
作为分隔符跳过开头strtok()
,但之后却找不到另一个标记结尾的令牌,所以字符串的其余部分被消耗掉了。因此,对(
的第二次调用无需处理并返回NULL。
固定代码避免了这个问题。初始分隔符必须包含,
才能跳过该分隔符,并且必须包含)
才能停止。第二个分隔符应包括strtoumax()
;其他字符并非严格需要。
由于您没有检查作为0
的第二个参数的输出指针,因此每次都可能为NULL(也称为strtoumax()
)。使用int
并将结果分配给strtoX()
有点奇怪。使用给定的数据,可以,但更一般地说,它可能会丢失重要信息。 errno
函数非常强大,但在报告超出界限值等方面也非常精细。这种用法会抛弃所有信息(在调用它之前你需要将uintmax_t
设置为0 ,您必须将值保存在char c;
if (sscanf(a, " (%d ,%d %c", &u, &v, &c) != 3 || c != ')')
…oops — malformatted data…
变量中,以准确获取和保存信息。
在这种情况下,解析输入字符串的方式更为简洁(但不一定更简单):
char c;
int n;
if (sscanf(a, " (%d ,%d %c%n", &u, &v, &c, &n) != 3 || c != ')' || temp[n] != '\0')
…Oops…
确保您知道为什么空间存在以及为什么它们在哪里。这可能需要仔细审查sscanf()
的POSIX规范。你可以决定没有空格;你需要知道这样做的后果是什么。如果要确保解析整个字符串,请使用:
%n
请注意,@Lob(type = LobType.CLOB)
转换规范不计算在内,因此3不会更改。
答案 1 :(得分:1)
@Jonathan Leffler给出的答案似乎很好地涵盖了原始代码中没有用的内容。我只是想我会添加一个解析包含包含未知长度的n元组的字符串的解决方案。这里,parsing()
函数将一个指向int
的指针的地址作为参数,这是一个模拟的数字数组将被存储的位置,以及一个输入字符串,应格式为{{1} }。我对使用格式错误输入的此函数的行为不做任何承诺。该函数分配空间,将数字存储在模拟数组中,并返回找到的数字。
我包含了一个显示已解析数字的函数,甚至在函数中将调用包装到"(int1, int2, ...)"
以捕获分配错误。我还添加了一些示例来说明它如何响应某些不同的输入。当然,由于我的realloc()
版本分配内存,调用者负责释放内存。
以下是代码:
parsing()
这是输出:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t parsing(int **nums, char *a);
void * xrealloc(void *ptr, size_t size);
void shownums(int *nums, size_t n);
int main(void)
{
int *nums = NULL;
size_t n;
char a[80] = "(6, 8)";
char b[80] = "(2, 3, 5)";
char c[80] = "(7)";
char d[80] = "(11,)";
char e[80] = "(2, 7, 1, 8, 2, 8, 1, 8, 2, 8, 5)";
n = parsing(&nums, a);
shownums(nums, n);
n = parsing(&nums, b);
shownums(nums, n);
n = parsing(&nums, c);
shownums(nums, n);
n = parsing(&nums, d);
shownums(nums, n);
n = parsing(&nums, e);
shownums(nums, n);
/* Free allocated memory */
free(nums);
return 0;
}
size_t parsing(int **nums, char *a)
{
size_t nums_sz = 0;
char *res;
while ((res = strtok(a, "(,)"))) {
nums_sz++;
*nums = realloc(*nums, sizeof(int) * nums_sz);
(*nums)[nums_sz - 1] = atoi(res);
a = NULL;
}
return nums_sz;
}
void * xrealloc(void *ptr, size_t size)
{
void *ret = realloc(ptr, size);
if (ret == NULL) {
fprintf(stderr, "Unable to allocate memory\n");
exit(EXIT_FAILURE);
}
return ret;
}
void shownums(int *nums, size_t n)
{
for (size_t i = 0; i < n; i++)
printf("%d ", nums[i]);
putchar('\n');
}