如何在 C 中将一个字符串分成多个特定长度的其他字符串?



主要情况下,我将一个字符串传递给应该分隔字符串的不同函数,然后使用每个子字符串。在这种情况下,我需要获取一个 30 个字符的字符串并将其分成长度为 7、5、5、7 和 6 的子字符串,以便稍后操作。这是我开始尝试的:

void breakString(const char *lineStr) {
        char a[7] = " "; //I tried with them all initialized empty and without doing so.
        char b[5];       //Didn't seem to make a difference.
        char c[5];
        char d[7];
        char e[6];
        //sscanf(lineStr, "%7s", &a);     //tried sscanf at first, but didn't know how to 
        strncpy(a, lineStr, 7);           //scan the middle so i switched to strncpy
        strncpy(b, lineStr + 7, 5);
        //continue this pattern for c,d,e
        (rest of function here, where each substring is manipulated accordingly.)

我通过打印子字符串ab(以及将它们strcmp()到正确的输出(来测试第一位,但它并不完全有效。我不断变得格外胡言乱语。例如,如果传递的完整字符串是 "abcdefghijklmnopqrstuvwxyz1234" ,则a"abcdefg"b"hijkl",依此类推。但是,当我打印a时,它显示为"abcdefg^#@%^&",每个子字符串后面都有一些随机分类的字符。

我做错了什么?还是有更好的方法来以不同的方式实现这一点?

我总是得到额外的胡言乱语...

这是因为如果源长度超过传递的大小,strncpy() 不会在目标末尾隐式追加 null 字符。在 C 语言中,字符串是以 null 结尾的字符数组。

因此,在此之后:

strncpy(a, lineStr, 7);

如果源长度超过传递的大小,则需要在末尾添加空字符,如下所示:

a[7] = '';

缓冲区大小应为 +1,以容纳缓冲区末尾的空字符:

char a[8];
char b[6];      
char c[6];
char d[8];
char e[7];

您应该尽量避免使用strncpy()因为您需要手动处理附加空字符。相反,请使用保证始终以 null 终止目标的东西,例如 snprintf() 。你可以做:

char a[8];
snprintf(a, 8, "%s", lineStr);

您无需附加终止空字符,它会自动附加到写入的内容之后。在此处阅读有关snprintf()的更多信息。


附加:

您尝试初始化空数组的方式不正确:

char a[7] = " "; 

这不是空数组,但这实际上将使用空格字符初始化数组(a[0])的第一个元素,其余元素将使用 0 初始化。要初始化空数组,您可以执行以下操作:

char a[8] = {0};

这将使用 0 初始化数组的所有元素。

你的问题可以用strncpy来解决,但你永远不应该使用这个函数,因为它的精确语义被广泛误解并且非常容易出错。

有关信息,请阅读 https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/。

此外,应使数组比计划为空终止符存储到其中的字符数长一个字节。

这是适合您情况的简单解决方案:

#include <stdio.h>
void breakString(const char *lineStr) {
    char a[7+1] = ""; /* destination strings must be initialized */
    char b[5+1] = ""; /* because the %c conversion specifier */
    char c[5+1] = ""; /* will set a null terminator. */
    char d[7+1] = "";
    char e[6+1] = "";
    if (strlen(lineStr) >= 7+5+5+7+6 &&
        sscanf(lineStr, "%7c%5c%5c%7c%6c", a, b, c, d, e) == 5) {
        /* string was long enough, fields correctly initialized */
        printf("a: %snb: %snc: %snd: %sne: %sn", a, b, c, d, e);
    }
}
int main() {
    breakString("abcdefghijklmnopqrstuvwxyz0123456789");
    return 0;
}

输出:

a: abcdefg
b: hijkl
c: mnopq
d: rstuvwx
e: yz0123

虽然此解决方案简单简洁,但我建议您采用不同的方法,使用实用程序函数。事实上,sscanf解决方案使用了一组非常不寻常的转换说明符,这将使大多数程序员扬眉吐气并拒绝它。此外,它不适合将可变数量的字符提取到适当大小的子数组中。

这是一种不同的方法:

#include <stdio.h>
size_t getchunk(char *dest, size_t n, const char *str) {
    size_t i;
    for (i = 0; i < n && *str; i++) {
        dest[i] = *str++;
    }
    dest[i] = '';
    return i;
}
void breakString(const char *lineStr) {
    char a[7+1];
    char b[5+1];
    char c[5+1];
    char d[7+1];
    char e[6+1];
    size_t pos = 0;
    pos += getchunk(a, 7, lineStr + pos);
    pos += getchunk(b, 5, lineStr + pos);
    pos += getchunk(c, 5, lineStr + pos);
    pos += getchunk(d, 7, lineStr + pos);
    pos += getchunk(e, 6, lineStr + pos);
    if (e[0] != '') {
        /* string was long enough, fields correctly initialized */
        printf("a: %snb: %snc: %snd: %sne: %sn", a, b, c, d, e);
    }
}
int main() {
    breakString("abcdefghijklmnopqrstuvwxyz0123456789");
    return 0;
}
1(

sscanf((

有了sscanf(),你可以做到

sscanf(lineStr, "%7c%5c%5c%7c%6c", a, b, c, d, e);
a[7]=b[5]=c[5]=d[7]=e[6]='';

%c可用于读取超过 1 个字节。 %7c最多读取 7 个字节。但不会自动添加。

感谢 chqrlie 的这种方法。

或者只是

sscanf(lineStr, "%7s%5s%5s%7s%6s", a, b, c, d, e);

如果lineStr中没有空格。

或者也许

sscanf(lineStr, "%7[^n]%5[^n]%5[^n]%7[^n]%6[^n]", a, b, c, d, e);

如果lineStr没有n字符。

其中格式字符串中的数字表示要复制的子字符串的宽度。

这样,您无需手动终止字符串。 sscanf()会照顾好它。


2( strncpy((

如果你必须使用'strncpy((,你就走在正确的轨道上。你可以做

void breakString(const char *lineStr) {
    char a[8];
    char b[6];      
    char c[6];
    char d[8];
    char e[7];
    strncpy(a, lineStr, 7);
    a[7]='';
    lineStr+=7;
    strncpy(b, lineStr, 5);
    b[5]='';
    lineStr+=5;
    strncpy(c, lineStr, 5);
    c[5]='';
    lineStr+=5;
    strncpy(d, lineStr, 7);
    d[7]='';
    lineStr+=7;
    strncpy(e, lineStr, 6);
    e[6]='';
    //lineStr+=6;
}

请注意,需要额外的一个字节来存储字符串的字符。因此,数组的大小会相应更改。

相关内容

  • 没有找到相关文章

最新更新