【问题标题】:ANSI C splitting stringANSI C 分割字符串
【发布时间】:2011-04-20 15:59:04
【问题描述】:

你好! 我陷入了一个 ANSI C 问题,我认为这应该是微不足道的(至少在任何现代语言中都是这样:/)。

我的脚本的(临时)目标是拆分一个包含 6 个字符(“123:45”)的字符串(char 数组),它表示时间戳分钟:秒(对于音频文件,因此可以有 120 分钟)只需几分钟和几秒钟。

我尝试了几种方法 - 一种是寻找“:”的通用方法,另一种是硬编码的,只是通过索引分割字符串,但似乎都不起作用。

void _splitstr ( char *instr, int index, char *outstr ) {
char temp[3]; 
int i; 
int strl = strlen ( instr );
if ( index == 0 ) {
    for ( i = 0; i < 3; ++i ) {
        if ( temp[i] != '\0' ) {
            temp[i] = instr[i];
        }
    }
} else if ( index == 1 ) {
    for ( i = 6; i > 3; i-- ) {
            temp[i] = instr[i];
        }
    }
strcpy ( outstr, temp );
}

另一个“有趣”的事情是 char[3] 的字符串长度是 6 或 9,实际上从来没有 3。这有什么问题?

【问题讨论】:

  • 家庭作业?没问题,请告诉我们
  • 您的代码尝试将 3 个字符放入 temp(它可以容纳),然后在“字符串”函数中使用 temp。字符串需要以空字节终止。您的temp 没有空字节空间。

标签: c string split ansi


【解决方案1】:

如何使用sscanf()。尽可能简单。

    char time[] = "123:45";
    int minutes, seconds;

    sscanf(time, "%d:%d", &minutes, &seconds);

如果您可以确定时间字符串语法始终有效,则此方法效果最佳。否则,您必须为此添加检查。成功时,sscanf 函数返回成功读取的项目数,因此也很容易检测到错误。

工作示例:http://ideone.com/vVoBI

【讨论】:

  • 天哪,这可以让我免去一整天的疯狂调试,谢谢!没想到这么简单>.>
【解决方案2】:

怎么样...

int seconds, minutes;
minutes = atoi(instr);
while(*instr != ':' && *++instr != '\0');
seconds = atoi(instr);

应该很快。

【讨论】:

  • 虽然我认为如果instr 碰巧不包含冒号字符,这可能会导致 SIGSEGV 或类似的崩溃(或可能产生无意义的结果),这有点苛刻。
  • @Simon Nickerson,@Athabaska Dick:确实如此。它不会原谅错误。我将添加NULL 检查。稍微慢一点,但应该不是问题;)
【解决方案3】:

你基本上有三个选择

  • 更改输入字符串(不能是字符串字面量)
  • 复制数据到输出字符串(输入可以是文字)
  • 将字符序列转换为数字

更改输入字符串意味着将 "123:45" 转换为 "123\0" "45" 并嵌入空值。

复制数据意味着管理副本的存储空间。

转换字符序列意味着使用例如strtol

【讨论】:

    【解决方案4】:

    您没有在 temp[] 中的字符串上放置终止 null,因此当您执行 strlen(temp) 时,您正在访问任意内存。

    使用您已知的长度,您可以使用如下内容:

    char temp[4];
    if (index==0)
    {
      strncpy(temp, instr, 3);
      temp[3] = 0;
    }
    else if (index==1)
    {
      strncpy(temp, instr+4, 2);
      temp[2] = 0;
    }
    strcpy(outstr, temp);
    

    但是,我要提醒的是,我已经跳过了对 instr 和 outstr 中有效长度的各种检查。

    【讨论】:

      【解决方案5】:

      你可以试试这样的:

      void break_string(const char* input, char* hours, char* minutes)
      {
          if(input == 0 || hours == 0 || minutes == 0)
              return;
      
          while(*input != ':')
              *hours++ = *input++;
      
          *hours = '\0';
          ++input;
      
          while(*minutes++ = *input++);
      
          return;
      }
      

      下面是同样的功能,稍微简化一下:

      void break_string(const char* input, char* hours, char* minutes)
      {
          if(input == 0 || hours == 0 || minutes == 0)
              return;
      
          while(*input != ':')
          {
              *hours = *input;
              ++hours;
              ++input;
          }
          *hours = '\0';
      
          ++input; //ignore the ':' part
          while(*input)
          {
              *minutes = *input;
              ++minutes;
              ++input;
          }
          *minutes = '\0';
      
          return;
      }
      
      int main()
      {
          char* test = "123:45";
          char* minutes   = malloc( sizeof(char) * 12 );
          char* hours     = malloc( sizeof(char) * 12 );
          break_string( test , hours , minutes );
          printf("%s , %s \n" , hours , minutes ); 
          //...
          free( minutes );
          free( hours ) ;
      }
      

      【讨论】:

      • 为什么要malloc 并复制一些已经在内存中的东西?你可以只保留两个指向原始字符串的指针。
      【解决方案6】:

      这个?

      char *mins, *secs;
      mins = str;
      while(*(++str) != ':');
      str[0] = '\0';
      secs = s + 1;
      

      【讨论】:

        【解决方案7】:

        这是一种方法,我忽略了上面的“索引”参数:

        #include <stdio.h>
        #include <string.h>
        
        void _splitstr ( char *instr, char *outstr ) {
                char temp[10];
                char* end = strchr(instr, ':');
                int i = 0;
        
                if(end != 0) {
                        while(instr != end)
                                temp[i++] = *instr++;
                        temp[i] = '\0';
                        strcpy(outstr, temp);
                } else {
                        outstr = '\0';
                }
        }
        

        【讨论】:

          猜你喜欢
          • 2011-08-09
          • 2015-12-09
          • 1970-01-01
          • 1970-01-01
          • 2012-10-21
          • 2020-11-22
          • 1970-01-01
          • 2022-09-28
          • 2015-01-21
          相关资源
          最近更新 更多