使用 strtok 转储的分段错误核心
Segmentation fault core dumped using strtok
我正在尝试编写自己的 scanf,它获取格式字符串中的数字以限制输入的大小。 like 而不是 "%d" 它使用 "@5%d" 表示输入不能超过 5 位数字。
我正在使用以下代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdarg.h>
/*
*
*/
char** str_split(char* a_str, const char a_delim);
void myscanf(char *input_format, ... );
int main(int argc, char** argv) {
int x;
myscanf("@2%d", &x);
printf("%d", x);
return 0;
}
void myscanf(char *input_format, ... ){
va_list args;
va_start(args, input_format);
char** tokens;
tokens = str_split(input_format, '@');
tokens=tokens++;
while(*tokens){
int number;
char format;
char** parts;
parts=str_split(*tokens,'%');
number=atoi(*(parts));
format= **(parts+1);
char s[number+1];
fgets(s,number+1,stdin);
if(strlen(s)>number)
perror("buffer overflow");
switch(format){
case 'd':{
int* integer = va_arg(args,int*);
*integer = atoi(s);
break;
}
case 'f': {
float* floatingpoint = va_arg(args,float*);
*floatingpoint = atof(s);
break;
}
case 'c': {
if(strlen(s)>1)
perror("buffer overflow");
char* character = va_arg(args,char*);
*character = s[0];
break;
}
case 's': {
char *string = va_arg(args,char*);
strcpy(string, s);
break;
}
}
tokens++;
}
}
char** str_split(char* a_str, const char a_delim)
{
char** result = 0;
size_t count = 0;
char* tmp = a_str;
char* last_comma = 0;
char delim[2];
delim[0] = a_delim;
delim[1] = 0;
/* Count how many elements will be extracted. */
while (*tmp)
{
if (a_delim == *tmp)
{
count++;
last_comma = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last_comma < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
result = (char **) malloc(sizeof(char*) * count);
if (result)
{
size_t idx = 0;
char* token = strtok(a_str, delim);
while (token)
{
assert(idx < count);
*(result + idx++) = strdup(token);
token = strtok(0, delim);
}
assert(idx == count - 1);
*(result + idx) = 0;
}
return result;
}
当我执行这个时,控制台显示
Segmentation fault core dumped.
我用gdb调试了一下,显示是strtok的问题。
gdb 输出:
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...(no debugging symbols found)...done.
/home/core: No such file or directory.
(gdb) r
Starting program: /home/a.out
Program received signal SIGSEGV, Segmentation fault.
strtok () at ../sysdeps/x86_64/strtok.S:186
186 ../sysdeps/x86_64/strtok.S: No such file or directory.
如果有人能解决这个问题,我将不胜感激。
您正在使用字符串文字 ("@2%d"
) 调用 myscanf
,myscanf
使用它调用 str_split
,str_split
将调用 strtok
并且 strtok
试图写入它,这是不允许的。
一个简单的解决方案是创建一个缓冲区
char buffer[] = "@2%d";
myscanf(buffer, &x);
我注意到的另一个小错误:
tokens=tokens++;
是未定义的行为,您应该只使用 tokens++;
来增加 tokens
。
您已经注意到我对 strcpy
的评论并在示例代码中对其进行了更改。
我正在尝试编写自己的 scanf,它获取格式字符串中的数字以限制输入的大小。 like 而不是 "%d" 它使用 "@5%d" 表示输入不能超过 5 位数字。
我正在使用以下代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdarg.h>
/*
*
*/
char** str_split(char* a_str, const char a_delim);
void myscanf(char *input_format, ... );
int main(int argc, char** argv) {
int x;
myscanf("@2%d", &x);
printf("%d", x);
return 0;
}
void myscanf(char *input_format, ... ){
va_list args;
va_start(args, input_format);
char** tokens;
tokens = str_split(input_format, '@');
tokens=tokens++;
while(*tokens){
int number;
char format;
char** parts;
parts=str_split(*tokens,'%');
number=atoi(*(parts));
format= **(parts+1);
char s[number+1];
fgets(s,number+1,stdin);
if(strlen(s)>number)
perror("buffer overflow");
switch(format){
case 'd':{
int* integer = va_arg(args,int*);
*integer = atoi(s);
break;
}
case 'f': {
float* floatingpoint = va_arg(args,float*);
*floatingpoint = atof(s);
break;
}
case 'c': {
if(strlen(s)>1)
perror("buffer overflow");
char* character = va_arg(args,char*);
*character = s[0];
break;
}
case 's': {
char *string = va_arg(args,char*);
strcpy(string, s);
break;
}
}
tokens++;
}
}
char** str_split(char* a_str, const char a_delim)
{
char** result = 0;
size_t count = 0;
char* tmp = a_str;
char* last_comma = 0;
char delim[2];
delim[0] = a_delim;
delim[1] = 0;
/* Count how many elements will be extracted. */
while (*tmp)
{
if (a_delim == *tmp)
{
count++;
last_comma = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last_comma < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
result = (char **) malloc(sizeof(char*) * count);
if (result)
{
size_t idx = 0;
char* token = strtok(a_str, delim);
while (token)
{
assert(idx < count);
*(result + idx++) = strdup(token);
token = strtok(0, delim);
}
assert(idx == count - 1);
*(result + idx) = 0;
}
return result;
}
当我执行这个时,控制台显示
Segmentation fault core dumped.
我用gdb调试了一下,显示是strtok的问题。 gdb 输出:
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...(no debugging symbols found)...done.
/home/core: No such file or directory.
(gdb) r
Starting program: /home/a.out
Program received signal SIGSEGV, Segmentation fault.
strtok () at ../sysdeps/x86_64/strtok.S:186
186 ../sysdeps/x86_64/strtok.S: No such file or directory.
如果有人能解决这个问题,我将不胜感激。
您正在使用字符串文字 ("@2%d"
) 调用 myscanf
,myscanf
使用它调用 str_split
,str_split
将调用 strtok
并且 strtok
试图写入它,这是不允许的。
一个简单的解决方案是创建一个缓冲区
char buffer[] = "@2%d";
myscanf(buffer, &x);
我注意到的另一个小错误:
tokens=tokens++;
是未定义的行为,您应该只使用 tokens++;
来增加 tokens
。
您已经注意到我对 strcpy
的评论并在示例代码中对其进行了更改。