将数组的一部分复制到自身?

时间:2015-12-06 03:18:22

标签: c arrays memory-management

基本上我正在构建一个位读取器,稍微在缓冲区耗尽之前,我想将数组中剩下的任何内容复制到同一个数组的开头,然后在复制之后将所有内容归零,并填充其余部分来自输入文件中的数据。

我只是出于可移植性的原因尝试使用标准库。

另外,我之前正在对我的位读取器进行剖析,而且仪器表示完成这一切需要花费28毫秒,它应该花费那么长时间吗?

删除了代码

1 个答案:

答案 0 :(得分:4)

我建议使用memmove作为副本。它具有与memcpy相同的签名和功能,除了在重叠区域之间复制是安全的(这就是您所描述的)。

对于零填充,memset通常就足够了。例如,在没有使用基础零序列表示空指针的情况下,您需要根据类型使用赋值来自行滚动。

出于这个原因,您可能希望隐藏抽象背后的memmovememset操作,例如:

#include <string.h>

void copy_int(int *destination, int *source, size_t size) {
    memmove(destination, source, size * sizeof *source);
}

void zero_int(int *seq, size_t size) {
    memset(seq, 0, size * sizeof *seq);
}

int main(void) {
    int array[] = { 0, 1, 2, 3, 4, 5 };
    size_t index = 2
         , size  = sizeof array / sizeof *array - index;
    copy_int(array, array + index, size);
    zero_int(array + size, index);
}

如果将来memmovememset变得不适合使用,那么放入你自己的副本/零循环就很简单了。

至于你的奇怪的探查器结果,我想你可能会使用一些过时的(或严重低频的)实现,或者试图复制巨大的阵列......否则,28毫秒看起来确实很荒谬。尽管如此,您的探查器肯定会确定此memmovememset不是执行实际I / O工作的程序中的重要瓶颈,对吧? I / O肯定是瓶颈,对吗?

如果memmove + memset确实是瓶颈,您可以尝试实现循环数组以避免副本。例如,以下代码尝试在比喻干草堆needle中找到input_file ...

否则,如果I / O是一个瓶颈,那么可以应用调整来减少这种情况。例如,以下代码使用setvbuf建议底层实现尝试使用底层缓冲区来读取文件的块,尽管代码使用fgetc一次读取一个字符。

void find_match(FILE *input_file, char const *needle, size_t needle_size) {
    char input_array[needle_size];
    size_t sz = fread(input_array, 1, needle_size, input_file);
    if (sz != needle_size) {
        // No matches possible
        return;
    }

    setvbuf(input_file, NULL, _IOFBF, BUFSIZ);
    unsigned long long pos = 0;
    for (;;) {
        size_t cursor = pos % needle_size;
        int tail_compare = memcmp(input_array, needle + needle_size - cursor, cursor),
            head_compare = memcmp(input_array + cursor, needle, needle_size - cursor);
        if (head_compare == 0 && tail_compare == 0) {
            printf("Match found at offset %llu\n", pos);
        }
        int c = fgetc(input_file);
        if (c == EOF) {
            break;
        }
        input_array[cursor] = c;
        pos++;
    }
}

注意这里不需要memmove(或归零,FWIW)吗?我们只是操作,好像数组的开头是cursor,结束于cursor - 1,我们用模needle_size换行以确保没有溢出/下溢。然后,在每次插入后,我们只需递增cursor ...