Strtok 没有按预期返回,是我用错了吗?
Strtok isn't returning as expected, am I using it wrong?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// fiter string to the first |
char* filterstringfirst(char* command, int i){
char *tok = command;
int x = 0;
while ((tok = strtok(tok, "|")) != NULL && x <= i)
{
if( x == i){
return tok;
}
x++;
printf(" === Parsed: --%s-- ===\n", tok);
tok = NULL;
}
return tok;
}
int main () {
char command[] = "ls -a | sort -h | grep h | wc -l";
char command2[] = "ls -a | sort -h | grep h | wc -l";
char* temp = command;
char* x = filterstringfirst(temp, 0);
printf("%s\n",x);
char* temp2 = command;
char* x2 = filterstringfirst(temp2, 1);
printf("%s\n",x2);
temp = command;
return 0;
}
我制作了这个函数,它应该只是字符串的 return 一部分。原始字符串应类似于“ls -l | grep temp | sort”。
当时的想法是使用字符串和数字以及 return 该段来调用它。例如。 0 -> “ls -l”
现在我第一次调用它时工作正常,但再次调用它似乎中断并以段错误结束。
char command[] = "ls -a | sort -h | grep h | wc -l";
char* temp = command;
char* x = filterstringfirst(temp, 0);
printf("%s\n",x);
char* temp2 = command;
char* x2 = filterstringfirst(temp2, 1);
printf("%s\n",x2);`
这是我的测试代码
并且输出:
ls -a
=== Parsed: --ls -a -- ===
[1] 1126 segmentation fault ./templ
➜ Current gcc -o templ templ.c
➜ Current ./templ ls -a
=== Parsed: --ls -a -- === [1]
1136 segmentation fault ./templ
编辑:更新为也有 main(基于评论)
函数strtok
通过在分隔符位置插入零个字符'\0'来更改传递的字符串。
所以在第一次调用函数后filterstringfirst
char* x = filterstringfirst(temp, 0);
字符数组command
看起来像
"ls -a [=11=] sort -h | grep h | wc -l";
^^^
事实上你有以下字符串 "ls -a "
存储在数组 command
.
中
因此第二次使用大于 0 的第二个参数调用该函数时,您将得到一个空指针。
如果您想提取指定索引的子字符串,那么您应该使用函数 strspn
和 strcspn
以及 return 从函数动态分配的包含目标子字符串的数组。
这是一个演示程序,展示了如何使用标准字符串函数 strspn
和 strcspn
以及 定义函数,而无需动态创建源字符串的副本 (这是低效且不安全的)每次调用函数时。
#include <string.h>
#include <stdlib.h>
#include <string.h>
char * filterstringfirst( const char *command, const char *delimiters, size_t i )
{
char *substring = NULL;
const char *p = command;
size_t n = 0;
do
{
p += n;
p += strspn( p, delimiters );
n = strcspn( p, delimiters );
} while (*p && i--);
if ( *p && ( substring = malloc( n + 1 ) ) != NULL )
{
memcpy( substring, p, n );
substring[n] = '[=12=]';
}
return substring;
}
int main( void )
{
char command[] = "ls -a | sort -h | grep h | wc -l";
const char *delimiters = "|";
char *substring = NULL;
for (size_t i = 0;
( substring = filterstringfirst( command, delimiters, i ) ) != NULL;
i++)
{
printf( "%zu: \"%s\"\n", i, substring );
free( substring );
}
}
程序输出为
0: "ls -a "
1: " sort -h "
2: " grep h "
3: " wc -l"
您可以将此函数与用于分隔字符串的任何定界符一起使用。
strtok
是 破坏性的 - 它通过替换定界符将空字节修改传入的缓冲区。
之后
char* x = filterstringfirst(temp, 0);
command
实际上是 "ls -a "
.
如果您想在此处使用 strtok
,您需要:
在包装函数中模仿strtok
,通过传递NULL
和后续调用的起始位置,或
在使用之前复制字符串,return 令牌的副本。
第二个示例,没有错误处理:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_token_at(char *command, size_t n) {
size_t position = 0;
char *copy = strdup(command);
char *token = strtok(copy, "|");
char *output = NULL;
while (token && position < n) {
token = strtok(NULL, "|");
position++;
}
if (token && position == n)
output = strdup(token);
free(copy);
return output;
}
int main(void) {
char command[] = "ls -a | sort -h | grep h | wc -l";
char *x = get_token_at(command, 0);
puts(x);
free(x);
x = get_token_at(command, 1);
puts(x);
free(x);
}
stdout
:
ls -a
sort -h
(注意这些标记中的空格。)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// fiter string to the first |
char* filterstringfirst(char* command, int i){
char *tok = command;
int x = 0;
while ((tok = strtok(tok, "|")) != NULL && x <= i)
{
if( x == i){
return tok;
}
x++;
printf(" === Parsed: --%s-- ===\n", tok);
tok = NULL;
}
return tok;
}
int main () {
char command[] = "ls -a | sort -h | grep h | wc -l";
char command2[] = "ls -a | sort -h | grep h | wc -l";
char* temp = command;
char* x = filterstringfirst(temp, 0);
printf("%s\n",x);
char* temp2 = command;
char* x2 = filterstringfirst(temp2, 1);
printf("%s\n",x2);
temp = command;
return 0;
}
我制作了这个函数,它应该只是字符串的 return 一部分。原始字符串应类似于“ls -l | grep temp | sort”。
当时的想法是使用字符串和数字以及 return 该段来调用它。例如。 0 -> “ls -l”
现在我第一次调用它时工作正常,但再次调用它似乎中断并以段错误结束。
char command[] = "ls -a | sort -h | grep h | wc -l";
char* temp = command;
char* x = filterstringfirst(temp, 0);
printf("%s\n",x);
char* temp2 = command;
char* x2 = filterstringfirst(temp2, 1);
printf("%s\n",x2);`
这是我的测试代码
并且输出:
ls -a
=== Parsed: --ls -a -- ===
[1] 1126 segmentation fault ./templ
➜ Current gcc -o templ templ.c
➜ Current ./templ ls -a
=== Parsed: --ls -a -- === [1]
1136 segmentation fault ./templ
编辑:更新为也有 main(基于评论)
函数strtok
通过在分隔符位置插入零个字符'\0'来更改传递的字符串。
所以在第一次调用函数后filterstringfirst
char* x = filterstringfirst(temp, 0);
字符数组command
看起来像
"ls -a [=11=] sort -h | grep h | wc -l";
^^^
事实上你有以下字符串 "ls -a "
存储在数组 command
.
因此第二次使用大于 0 的第二个参数调用该函数时,您将得到一个空指针。
如果您想提取指定索引的子字符串,那么您应该使用函数 strspn
和 strcspn
以及 return 从函数动态分配的包含目标子字符串的数组。
这是一个演示程序,展示了如何使用标准字符串函数 strspn
和 strcspn
以及 定义函数,而无需动态创建源字符串的副本 (这是低效且不安全的)每次调用函数时。
#include <string.h>
#include <stdlib.h>
#include <string.h>
char * filterstringfirst( const char *command, const char *delimiters, size_t i )
{
char *substring = NULL;
const char *p = command;
size_t n = 0;
do
{
p += n;
p += strspn( p, delimiters );
n = strcspn( p, delimiters );
} while (*p && i--);
if ( *p && ( substring = malloc( n + 1 ) ) != NULL )
{
memcpy( substring, p, n );
substring[n] = '[=12=]';
}
return substring;
}
int main( void )
{
char command[] = "ls -a | sort -h | grep h | wc -l";
const char *delimiters = "|";
char *substring = NULL;
for (size_t i = 0;
( substring = filterstringfirst( command, delimiters, i ) ) != NULL;
i++)
{
printf( "%zu: \"%s\"\n", i, substring );
free( substring );
}
}
程序输出为
0: "ls -a "
1: " sort -h "
2: " grep h "
3: " wc -l"
您可以将此函数与用于分隔字符串的任何定界符一起使用。
strtok
是 破坏性的 - 它通过替换定界符将空字节修改传入的缓冲区。
之后
char* x = filterstringfirst(temp, 0);
command
实际上是 "ls -a "
.
如果您想在此处使用 strtok
,您需要:
在包装函数中模仿
strtok
,通过传递NULL
和后续调用的起始位置,或在使用之前复制字符串,return 令牌的副本。
第二个示例,没有错误处理:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_token_at(char *command, size_t n) {
size_t position = 0;
char *copy = strdup(command);
char *token = strtok(copy, "|");
char *output = NULL;
while (token && position < n) {
token = strtok(NULL, "|");
position++;
}
if (token && position == n)
output = strdup(token);
free(copy);
return output;
}
int main(void) {
char command[] = "ls -a | sort -h | grep h | wc -l";
char *x = get_token_at(command, 0);
puts(x);
free(x);
x = get_token_at(command, 1);
puts(x);
free(x);
}
stdout
:
ls -a
sort -h
(注意这些标记中的空格。)