C 如何使用循环缓冲区解决此问题?

C 如何使用循环缓冲区解决此问题?,c,circular-buffer,C,Circular Buffer,在不必使用for循环重新排列所有元素的情况下,在数组中先插入一个元素,最有效的方法是什么。我尝试过循环缓冲区实现,但它不起作用,我感到沮丧。我把问题简化了,希望大家都能轻松些 int * buffer = (int *) calloc(L_buffer, sizeof(int)); int i, j, K, out; while(1) { i = rand(); K = 3; /* Calculate output */ out = buffer[i]

在不必使用for循环重新排列所有元素的情况下,在数组中先插入一个元素,最有效的方法是什么。我尝试过循环缓冲区实现,但它不起作用,我感到沮丧。我把问题简化了,希望大家都能轻松些

int * buffer = (int *) calloc(L_buffer, sizeof(int));
int i, j, K, out;

while(1) {

    i = rand();
    K = 3;

    /* Calculate output */

    out = buffer[i]  buffer[i+1]  + buffer[K];

    /* Shift array elements by one and insert new value */

    for(j = 0; j < L_buffer-1; j++) 
        buffer[j+1] = buffer[j];

    buffer[0] = new_value;
}
真漂亮

也许有一种更优雅的方式,比用这么多的台词来表达更优雅

“mod”使用无符号数学使用
%L\u array
访问数组索引。此外,如果
L_数组
是一个无符号的2次幂,
%L_数组
只会发出和编码


注意:
--p_dynamic
永远不会为真,除非代码依赖于未定义的行为。要比较
p\u dynamic
的有效值是
array[0]…array[length]
,其中不包括
array[-1]

循环缓冲区的插入看起来可疑。对于
循环移位,应该没有理由使用
。而是调整对缓冲区末端的引用

考虑使用以下方法:

array = calloc(L_array, sizeof *array);
size_t length = 0; // current length
size_t begin = 0;  // Index of eldest sample
size_t end = 0;    // Index to store the next sample
插入

if (length < L_array) {
  length++;
  array[end] = new_value;
  end = (end+1)%L_array;
}
i

if (length >= 3) {
  output = array[(begin+i) % L_array] + array[(begin+i+1) % L_array] +
      array[(begin+i+2) % L_array];
}
int*p_dynamic=array[0];
int*p_start=array[0];
int*p_end=数组[L_数组-1]

您没有告诉我们这些变量的用途,因此我们不知道您是否以合理的方式使用它们来达到预期目的

if(-p\u动态

p\u dynamic
指向
array[0]
时,
--p\u dynamic
的行为不由C标准定义。该标准仅定义从数组的元素0到数组的最后一个元素之外的指针算法

intk=3;
int i=一些int;
整数输出;
输出=阵列[i]+阵列[i+1]+阵列[K]

再一次,你没有告诉我们你的意图,所以我们不知道你在这里想要实现什么。为什么
K
3?这是您每次使用代码时的固定常数,还是只是一个示例?它是否与
i
有任何关系?您的意思是说将始终添加实际元素
array[K]
,还是说将添加距循环缓冲区当前起点偏移量3处的元素

if(p_动态[K]>p_结束&&
p_动态[i]

这没有意义,因为
p\u dynamic
是指向
int
的指针,所以
p\u dynamic[K]
int
,但是
p\u end
是指向
int
的指针,所以
p\u dynamic[K]>p\u end
尝试将
int
与指针进行比较。我怀疑您试图询问元素
p\u dynamic[K]
是否超出数组的末尾。您可以使用
p_dynamic+K>p_end
执行此操作,但与
--p_dynamic
一样,如果指针超出数组的末尾,则指针算法不由C标准定义

通过创建一个函数来帮助您访问数组元素,从而简化代码。制作一个描述循环缓冲区的结构。简单地说,我假设您有一个固定的缓冲区大小
size
elements

typedef struct
{
    int array[Size];
    ptrdiff_t current;
} CircularBuffer;
成员
current
将是缓冲区中当前最早的元素的索引(下标),即循环缓冲区的当前“开始”。(标题
中定义了
ptrdiff\u t
类型。它可以用于数组下标

然后创建一个函数,为您提供一个指向具有索引
i
的元素的指针:

int *CBElement(CircularBuffer *cb, ptrdiff_t i)
{
    ptrdiff_t index = i + current;
    if (Size <= index) index -= Size;
    return &cb->array[index];
}
您还可以在数组中放入新值:

*CBElement(&cb, i) = NewValue;
要推进缓冲区,请以明显的方式更新当前成员,并在新的最后一个元素(
*CBElement(&cb,Size-1)
)中添加新值


<>这将简化代码工作的任务。在它工作之后,你可以考虑缓冲区实现的优化和改进。

你指的是“但它不工作”和“类工作”是什么意思??这是一个音频效果。第一个版本只是完全扭曲了信号。最后一个版本产生了适当的效果,但也有一些小故障,如弹出噪音。也许最后一个版本实际上是正确的。如果是这样,错误就在其他地方。我觉得这不正确:
If(-p_dynamic
为什么不干脆…
p[计数器+++%length]
?(
计数器
用于
i
K
或…)@M.NejatAydin为什么不呢?我首先递减,如果移动指针低于第一个地址,我会转到缓冲区中的最后一个地址。几秒钟前,我刚刚尝试了使用模的解决方案,但它也有问题。我也无法将指针与数组索引进行比较,因为我使用calloc分配了内存。因此,我存储了第一个d分配后的最后一个条目,并且我使用指向分配内存的指针是p_动态的。我不能在这里使用数组,因为所有这些都发生在中断例程中。循环缓冲区是及时完成这一任务的唯一方法。处理器有225 MHz。@neolith建议的编码方法不使用数组,而是使用指针和3 in影响循环缓冲区的tegers。我已经在中断服务例程中成功地多次编写了这样的孤子。给定在中断中调整数据,任何非ISR访问和对缓冲区的操作都可以保证在短时间内免受中断的影响。CPU速度不是问题。我使问题变得更容易,因为我得到了我自己用过。希望能有帮助。很抱歉,如果你到目前为止的努力都是徒劳的。我相应地编辑了代码。这不是一个数组,而是分配的内存。因此我可以自由移动指针。我会试着看看我是否能写一个函数。我认为没有完整的代码,这个问题太复杂了。但是当你发布完整的代码时,人们抱怨说你应该描述它。这样我就可以
if (length >= 3) {
  output = array[(begin+i) % L_array] + array[(begin+i+1) % L_array] +
      array[(begin+i+2) % L_array];
}
typedef struct
{
    int array[Size];
    ptrdiff_t current;
} CircularBuffer;
int *CBElement(CircularBuffer *cb, ptrdiff_t i)
{
    ptrdiff_t index = i + current;
    if (Size <= index) index -= Size;
    return &cb->array[index];
}
output = *CBElement(&cb, i) + *CBElement(&cb, i+1) + *CBElement(&cb, K);
*CBElement(&cb, i) = NewValue;