如何在调用atoi之前将指针设置为NULL

时间:2014-01-05 11:35:52

标签: c string

我是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

3 个答案:

答案 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);

很好,只要

  1. 我们忽略atoi,因为不推荐使用它:输入必须是“好”
  2. 我们不需要知道支票的结果 - 这听起来很棒(为什么我们检查?)
  3. 如果您担心会损坏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)

你不应该使用atoistrtol(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;
}