将字符串转换为布尔数组

3
我需要将由一百万个“零”或“一”字符(具体为1039680个字符)组成的字符串转换为布尔数组。目前我的方法对于300000个字符的字符串需要几秒钟,这太长了。我需要能在不到一秒钟内完成整个百万字符的转换。
我的尝试是读取一个包含一行(在这个试验中为300000个零)的文件。
我知道如果字符串中包含其他内容,我的代码会出现问题,但我知道该字符串只包含那些字符。
我还查看了atoi,但我认为它不适合我的需求。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define BUFFERSIZE 1039680

int main ()
{
    int i ;
    char buffer[BUFFERSIZE];
    bool boolList[BUFFERSIZE] ;

    // READ FILE WITH A LOT OF ZEROS
    FILE *fptr;
    if ((fptr=fopen("300000zeros.txt","r"))==NULL){
        printf("Error! opening file\n");
        exit(1);
    }
    fscanf(fptr,"%[^\n]",buffer);
    fclose(fptr);

    // CONVERT STRING TO BOOLEAN ARRAY
    for (i=0 ; i<strlen(buffer) ; i++) {
        if (buffer[i] == '1') boolList[i] = 1 ;
    }

    return 0;
}

7
你尝试过在循环之前缓存strlen()的调用吗?也许你的编译器在每次迭代中都在计算字符串的长度。 - Darien Pardinas
3
你也可以在不使用长度的情况下进行迭代,并在到达空字符时停止。 - Rufflewind
1
@Rufflewind 只需要对数组进行一次解析,而且不使用 strlen() 函数也可以完成。 - Gopi
1
因为你的编译器没有优化对 strlen 的重复调用。不是只调用一次并将 i<strlen(buffer) 替换为计算出的值,而是在 for 循环的每次迭代中都会调用 strlen,导致 buffer 被迭代了 300k 次。Rufflewind 的解决方案仍然更好。 - foobar
1
你使用的编译器是什么?你使用了任何编译器优化选项吗? - user12205
显示剩余6条评论
2个回答

4

尝试

char *sptr = buffer;
bool *bptr = boolList;
while (*sptr != '\0')
    *bptr++ = *sptr++ == '1'? 1:0;

正确。然而,这种“压缩”的代码不应该没有文档就被使用。这样做并不酷,至少在SO上回答问题时是这样的。此外,它很可能无法通过任何生产代码审查。-1 - alk

2
如果字符串长度像您所说的那样始终为1039680个字符,那么为什么在您的代码中使用strlen(buffer)呢?为什么不只是循环BUFFERSIZE次?如果字符串长度可以以某种方式更改,则应该像其他人建议的那样将其缓存到变量中,而不是每次循环都调用它。
更重要的是,您没有在缓冲区中包含NULL终止字节的空间,因此当您读取确切的BUFFERSIZE个字符时,字符数组不是一个有效的NULL终止字符串,因此对它调用strlen会引起未定义行为。
如果您想将文件读取为文本,则必须在缓冲区中再添加一个字符。
char buffer[BUFFERSIZE + 1];

否则,以二进制形式打开文件,并一次性读取整个1039680字节的块。这样会更快。
fread(buffer, sizeof(buffer[0]), BUFFERSIZE, fptr);

然后只需循环读取BUFFERSIZE字节并将其设置为0,无需分支。

for (i = 0 ; i < BUFFERSIZE; i++)
{
    buffer[i] -= '0';
}

您不需要另一个boolList,只需将buffer用作boolList或将名称更改为boolList并丢弃缓冲区。

这样,char缓冲区被转换为bool缓冲区了吗? - Gordian
只有当 sizeof(char) == sizeof(bool) 时,你才能这样转换。否则,你需要使用单独的数组,但你仍然可以像这样得到一个无分支的解决方案:boolList[i] = buffer[i] - '1'。但是为什么不直接使用 char 呢?除非你要将它传递给其他接口,否则在你的情况下 char 已经足够了。 - phuclv
1
这是解决这个问题的正确方法,除了在char buffer[BUFFERSIZE + 1];中没有必要使用BUFFERSIZE + 1char buffer[BUFFERSIZE];就可以了。 - chux - Reinstate Monica
@chux,但是如果没有+1,strlen函数将无法按预期工作。 - phuclv
  1. 在读取时,buffer 被视为数组而不是字符串。
  2. buffer[BUFFERSIZE] 从未设置为任何值,因此它对于作为字符串的 '\0' 终止符没有帮助。
  3. buffer[i] -= '0' 导致了一个由 '\0'(空字符)和 '\1' 组成的数组。这对于打印字符串来说并没有太大意义。
- chux - Reinstate Monica
@chux 我对 [set] 修饰符的理解有误。如果 OP 在缓冲区上调用 strlen,那么它应该是一个以 NULL 结尾的字符串。 - phuclv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接