【问题标题】:Copy part of array to itself?将数组的一部分复制到自身?
【发布时间】:2015-12-06 03:18:21
【问题描述】:

基本上我正在构建一个阅读器,在缓冲区耗尽之前,我想将数组剩余的内容复制到同一个数组的开头,然后在复制后将所有内容归零,然后填充其余的是输入文件中的数据。

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

另外,我之前正在分析我的位阅读器,Instruments 说完成所有这些需要大约 28 毫秒,它应该需要那么长时间吗?

代码已删除

【问题讨论】:

  • 虽然我开始认为我应该跳过所有这些,而是​​将文件倒回到最后一个未读字节,然后简单地从那里读取,直到缓冲区已满......
  • memcpy(如果没有重叠)或memmove(如果有重叠)。除非你告诉我们你正在处理的输入大小,你运行它的硬件等,否则 28 毫秒是没有意义的。
  • 我将用 1 秒的示例进行编辑。
  • @Ike InputBuffer 是 4096 字节,并不是一个庞大的数据集。事实上,在大多数系统上它应该正好是一页内存。

标签: c arrays memory-management


【解决方案1】:

我建议使用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 确实是一个瓶颈,您可以尝试实现一个循环数组来避免复制。例如,下面的代码试图在input_file这个比喻性的大海捞针中找到needle...

否则,如果 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...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-03
    • 1970-01-01
    • 1970-01-01
    • 2015-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多