我是C的新手,在调用atoi之前,我似乎不知道如何将指针* year设置为NULL。我有下面的代码将我的字符串分成4,当我运行它时,它会抛出程序,我确定这是因为我插入了atoi函数。 你能帮我吗?
char *split(char words[50])
{
int i = 0;
char* words_dup = malloc(strlen(words)+1);
strcpy(words_dup,words);
while (words!='\0')
{
char *word=strtok(words, "_#_");
check_word(*word);
char *year=strtok(NULL, "_#_");; // assigning NULL for previousely where it left off
i=atoi(year);
check_year(i);
char *definition=strtok(NULL,"_#_");
check_definition(*definition);
char *synonyms=strtok(NULL,"_#_");
check_synonyms(*synonyms);
printf("%s\t", word);
printf("%i\t",i);
printf("%s\t", definition);
printf("%s\t", synonyms);
}
// now restore words
strcpy(words,words_dup);
free(words_dup);
return 0;
}
//------------------------------------------------------------------//
// CHECKING LEGAL OR NOT
//------------------------------------------------------------------//
void check_word(char word)
{
if (word>='A' && word<='Z')
{
printf("not legal\n");
}
}
void check_year(int year)
{
if (year<0)
{
printf("not legal\n");
}
}
void check_definition(char definition)
{
if (definition>='A' && definition<='Z')
{
printf("not legal\n");
}
}
void check_synonyms(char synonym)
{
if (synonym>='a' && synonym<='z')
{
printf("not legal\n");
}
}
int main()
{
char words[100];
printf("Enter a string\n");
scanf("%s", words);
split(words);
}
这就是我要输入的内容:hello_#_2003_#_now_#_MY
答案 0 :(得分:1)
您不应该使用atoi
,因为它不允许您知道它是否无法解析其输入,但无论如何都会返回一个int。但是为了练习,让我们假设它是好的,因为输入是好的(即有符号整数)。
然后,关于你的代码的一些注释:
split
无需返回char *
,实际上您将其称为返回void,因此将其拆分为void split…
;在任何情况下,保留char *split…
,它应该返回NULL
,而不是0
。
这些行
char* words_dup = malloc(strlen(words)+1);
strcpy(words_dup,words);
可以简单地
char *words_dup = strdup(words);
然后,
while (words!='\0')
words
是一个指针(char *
),而不是一个字符,所以它应该是*words
或者你的意思是words != NULL
,但是words
isn' t变成了循环,所以你将永远循环。
我想你的意思是在一个连续的流中解析包含单词,年份,定义,同义词的“块”的“流”。
如果是,则只需word = strtok(words, "_#_")
一次,然后使用word = strtok(NULL, "_#_")
。你可以用
char *word;
// use words_dup to avoid changing words.
for (word = strtok(words_dup, sep); word != NULL; word = strtok(NULL, sep))
{
check_word(word);
// ...
}
(通常,每次尝试获取新信息时,都应检查strtok是否返回NULL;如果需要,可以使用break
退出for循环。
如果不那么,则根本不需要循环:如果您有多行,请为输入的每一行调用“split”。
"_#_"
的使用可能因为您想要的原因而无法工作(该参数是一组字符,每个都被视为一个分隔符),但是从那时起:
解析后的两个或多个连续分隔符字节的序列 string被认为是一个单独的分隔符
代码
char *year=strtok(NULL, "_#_");; // assigning NULL…
i=atoi(year);
check_year(i);
很好,只要
atoi
,因为不推荐使用它:输入必须是“好”如果您担心会损坏words
,请在第一个words_dup
中使用strtok
,最后只需要free
!
free(words_dup);
check_word
是一个误导性的名称:你只检查第一个字符(在其他函数中)。
check_*
函数不会返回任何内容,因此您无法在调用者中对检查结果做出决定:“单词”是“不合法”,然后是调用者的假设({ {1}})应该做什么?你的程序继续,用户阅读split
,没有他/她可以确切地知道什么是不合法的:“字”或“年”,或“定义”(再次,它的第一个char)......?
(你想要这个吗?那么......)
你应该写一个像这样的函数
not legal
如果所有字符都是小写,则返回1 iff(这不是更好的方法,但我想你不能使用int is_lowecase(const char *str)
{
while (*str != '\0') {
if (*str < 'a' || *str > 'z') return 0;
str++;
}
return 1; // anything != 0 is "read" as true
}
)。
然后是来电者,例如islower
,可能是:
check_word
调用者可以考虑返回代码并决定停止对非法部分进行解析( int check_word(const char *word)
{
// only all lowercase words are legal
if (!is_lowercase(word)) {
// fprintf(stderr, "...");
// indeed I think it should be a caller duty to print
// such messages
printf("word: not legal\n");
return 0;
}
return 1;
}
)。如果您不需要,请更改回break
签名。否则,这个想法是:
void func(...)
(如果您不知道 if (!check_A_Test(datum)) {
// false (0) is Wrong, true (!= 0) is Right, thus the !
// message here, if you want
break; // stop parsing
}
,请将其删除。)
您可以对check_definition和check_synonyms使用完全相同的函数const
。
答案 1 :(得分:0)
你不应该使用atoi
而strtol(3)使用非空结束指针(或sscanf(3) ...):
long i;
char* end = NULL;
i = strtol(year, &end, 0);
if (i>0 && end>year) {
check_year(i);
// do something
}
else {
fprintf(stderr, "bad year: %s\n, year);
exit(EXIT_FAILURE);
}
然后使用end
做一些合理的事情,或许将其传递给strtok
或者可能传递给strstr(3)或strchr(3)以找到相关的下一个字符[s] ...... < / p>
我相信您对strtok(3)的使用是错误的。也许考虑sscanf(3)或许%n
。有关类似问题,请参阅this answer。
我不明白你的输入究竟是什么,但也许你只是想:
bool parse_line(const char*line, int* pyear)
{
int pos= -1;
int year=0;
if (sscanf(line, "%*[a-z]_#_%d_#_%*[a-z] %n", &year, &pos)>0 && pos>0
&& pos == strlen(line)) {
*pyear = year;
return true;
} else return false;
}
您稍后会致电(使用getline(3)或fgets(3)阅读整个line
后)
int yearnum=0;
if (parse_line(line, &yearnum))
check_year(yearnum);
else printf("not legal\n");
不要忘记编译所有警告和调试信息(例如gcc -Wall -g
)和使用调试器(例如gdb
),特别是要一步一步地运行你的错误程序!
答案 2 :(得分:0)
样品
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *str_dup(const char *str){//use strdup if exist strdup
char *sdup = malloc(strlen(str)+1);
if(sdup)
return strcpy(sdup, str);
return NULL;
}
char *strtokByWord_r(char *str, const char *word, char **store){
char *p, *ret;
if(str != NULL){
*store = str;
}
if(*store == NULL) return NULL;
p = strstr(ret=*store, word);
if(p){
*p='\0';
*store = p + strlen(word);
} else {
*store = NULL;
}
return ret;
}
char *strtokByWord(char *str, const char *word){
static char *store = NULL;
return strtokByWord_r(str, word, &store);
}
typedef struct record {
char *word;
int year;
char *definition;
char *synonyms;
} Record;
Record *get_rec(const char *input_string){
Record *rec;
char* words_dup = str_dup(input_string);
rec = malloc(sizeof(Record));
char *word=strtokByWord(words_dup, "_#_");
//if(check_word(word)!=Valid)
//{ fprintf(stderr, "bad format\n"); free(rec);/*free(words_dup);...*/ return NULL;}
rec->word = str_dup(word);
char *year=strtokByWord(NULL, "_#_");
rec->year =atoi(year);
char *definition=strtokByWord(NULL,"_#_");
rec->definition = str_dup(definition);
char *synonyms=strtokByWord(NULL,"_#_");
char *newline = strchr(synonyms, '\n');
if(newline)
*newline = '\0';
rec->synonyms = str_dup(synonyms);
free(words_dup);
return rec;
}
int main(void){
const char *input = "hello_#_2003_#_now_#_MY\n";
Record *r = get_rec(input);
printf("%s\t", r->word);
printf("%i\t",r->year);
printf("%s\t", r->definition);
printf("%s\n", r->synonyms);
free(r->word);free(r->definition);free(r->synonyms);
free(r);
return 0;
}
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
bool is_lowers(const char *str){
for(; *str ; ++str)
if(!islower(*str))
return false;
return true;//if call is_lowers("") then should be return value is true or false ?
}
int main(void){
char word[] = "word";
if(is_lowers(word))
printf("valid\n");
else
printf("invalid\n");
word[0] = 'W';
if(is_lowers(word))
printf("valid\n");
else
printf("invalid\n");
return 0;
}