【问题标题】:Copying specific number of characters from a string to another将特定数量的字符从一个字符串复制到另一个
【发布时间】:2020-12-07 03:17:46
【问题描述】:

我有一个可变长度的字符串,我试图将它与加号分开并研究:

            char string[] = "var1+vari2+varia3";
            for (int i = 0; i != sizeof(string); i++) {               
                memcpy(buf, string[0], 4);
                buf[9] = '\0';
            }

由于变量的大小不同,我正在尝试编写一些将字符串带入循环并提取(除)变量的东西。有什么建议 ?我期待这样的结果:

var1
vari2
varia3

【问题讨论】:

  • 寻找+ 字符的循环有什么问题?或者使用标准库函数,如strtok
  • 另外,在memcpy 中使用string[0] 是非常错误的,你的编译器应该已经警告你了。应该是string。

标签: c string buffer


【解决方案1】:

你的代码没有任何意义。

我为你写了这样一个函数。分析它,有时有一些代码作为基础是好的

char *substr(const char *str, char *buff, const size_t start, const size_t len)
{
    size_t srcLen;
    char *result = buff;

    if(str && buff)
    {
        if(*str)
        {
            srcLen = strlen(str);
            if(srcLen < start + len)
            {
                if(start < srcLen) strcpy(buff, str + start);
                else buff[0] = 0;          
            }
            else
            {
                memcpy(buff, str + start, len);
                buff[len] = 0;
            }
        }
        else
        {
            buff[0] = 0;
        }
    }
    return result;
}

https://godbolt.org/z/GjMEqx

【讨论】:

  • 恐怕substr("a", buf, 1, SIZE_MAX) 有未定义的行为。
  • 是的,谁在乎呢?甚至不值得检查。
【解决方案2】:

您可以使用简单的循环扫描字符串中的+ 符号:

    char string[] = "var1+vari2+varia3";
    char buf[sizeof(string)];
    int start = 0;
    for (int i = 0;;) {
        if (string[i] == '+' || string[i] == '\0') {
            memcpy(buf, string + start, i - start);
            buf[i - start] = '\0';
            // buf contains the substring, use it as a C string
            printf("%s\n", buf);
            if (string[i] == '\0')
                break;
            start = ++i;
        } else {
            i++;
        }
    }
        

【讨论】:

    【解决方案3】:

    您可以使用strtok()通过分隔符来分隔字符串

       char string[]="var1+vari2+varia3";
       const char delim[] = "+";
       char *token;
       
       /* get the first token */
       token = strtok(string, delim);
       
       /* walk through other tokens */
       while( token != NULL ) {
          printf( " %s\n", token );
        
          token = strtok(NULL, delim);
       }
    

    更多关于strtok()的信息在这里:https://man7.org/linux/man-pages/man3/strtok.3.html

    【讨论】:

    • 如果您希望它稍后在程序中使用,请确保不要标记原始 string。
    【解决方案4】:

    在我看来,您不仅想打印单个字符串,还想将单个字符串保存在某个缓冲区中。

    由于您不知道字符串的数量或单个字符串的长度,因此您应该动态分配内存,即使用 realloc, calloc and malloc 之类的函数。

    它可以通过多种方式实现。下面是一个例子。为简单起见,无论如何都没有对性能进行优化。

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <assert.h>
    
    char** split_string(const char* string, const char* token, int* num)
    {
        assert(string != NULL);
        assert(token != NULL);
        assert(num != NULL);
        assert(strlen(token) != 0);
    
        char** data = NULL;
        int num_strings = 0;
        while(*string)
        {
           // Allocate memory for one more string pointer
           char** ptemp = realloc(data, (num_strings + 1) * sizeof *data);
           if (ptemp == NULL) exit(1);
           data = ptemp;
           
           // Look for token
           char* tmp = strstr(string, token);
           
           if (tmp == NULL) 
           {
               // Last string
               // Allocate memory for one more string and copy it
               int len = strlen(string);
               data[num_strings] = calloc(len + 1, 1);
               if (data[num_strings] == NULL) exit(1);
               memcpy(data[num_strings], string, len);
    
               ++num_strings;    
               
               break;
           }
           
           // Allocate memory for one more string and copy it
           int len = tmp - string;
           data[num_strings] = calloc(len + 1, 1);
           if (data[num_strings] == NULL) exit(1);
           memcpy(data[num_strings], string, len);
           
           // Prepare to search for next string
           ++num_strings;
           string = tmp + strlen(token);
        }
        
        *num = num_strings;
        return data;
    }
    
    int main()
    {
        char string[]="var1+vari2+varia3";
        
        // Split the string into dynamic allocated memory
        int num_strings;    
        char** data = split_string(string, "+", &num_strings);
    
        // Now data can be used as an array-of-strings
        
        // Example: Print the strings
        printf("Found %d strings:\n", num_strings);
        for(int i = 0; i < num_strings; ++i) printf("%s\n", data[i]);
        
        // Free the memory
        for(int i = 0; i < num_strings; ++i) free(data[i]);
        free(data);
    
    }
    

    输出

    Found 3 strings:
    var1
    vari2
    varia3
    

    【讨论】:

    • @chqrlie 我相信你的观点很好,但我不确定我是否完全理解你的评论。它是输入示例吗?如果是这样,我不明白 "+" 会给 one 空字符串 - 而不是两个
    • 另一个极端情况是如果token 是一个空字符串。 split_string() 在这种情况下运行一个无限循环。
    • @chqrlie 意图是"" 给出零字符串,"+" 给出一个空字符串。 "++" 给出两个空字符串。换句话说
    • 确实尾随+ 不会导致产生尾随空字符串。我不确定这是否正确,因为初始 "+" 确实会产生初始空字符串。
    • @chqrlie 是的,一个空令牌......这是一个错误。我应该检查一下(或者只是说用空令牌调用是 UB :)
    猜你喜欢
    • 1970-01-01
    • 2012-05-09
    • 2021-08-28
    • 2010-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多