如何在C中进行就地计算

时间:2017-11-21 08:22:15

标签: c io in-place

我正在进行简单的就地傅立叶变换。但我不知道原地是如何发生的。例如,以下代码段取自https://rosettacode.org/wiki/Fast_Fourier_transform#C

由于函数声明void fft(cplx buf[], int n),没有任何输出,子函数中buf的变化如何转回主函数?

#include <stdio.h>
#include <math.h>
#include <complex.h>

double PI;
typedef double complex cplx;

void _fft(cplx buf[], cplx out[], int n, int step)
{
if (step < n) {
    _fft(out, buf, n, step * 2);
    _fft(out + step, buf + step, n, step * 2);

    for (int i = 0; i < n; i += 2 * step) {
        cplx t = cexp(-I * PI * i / n) * out[i + step];
        buf[i / 2]     = out[i] + t;
        buf[(i + n)/2] = out[i] - t;
    }
}
}

void fft(cplx buf[], int n)
{
cplx out[n];
for (int i = 0; i < n; i++) out[i] = buf[i];

_fft(buf, out, n, 1);
}


void show(const char * s, cplx buf[]) {
printf("%s", s);
for (int i = 0; i < 8; i++)
    if (!cimag(buf[i]))
        printf("%g ", creal(buf[i]));
    else
        printf("(%g, %g) ", creal(buf[i]), cimag(buf[i]));
}

int main()
{
PI = atan2(1, 1) * 4;
cplx buf[] = {1, 1, 1, 1, 0, 0, 0, 0};

show("Data: ", buf);
fft(buf, 8);
show("\nFFT : ", buf);

return 0;
}

我不确定我是否明确了这个问题。我在下面写了一个片段,与上面的片段结构相同。但是,它在就地模式下不起作用,我的意思是,子函数中变量的值变化没有转移到主函数中。

#include <stdio.h>

void _sumab(int a, int b, int c)
{
printf("2: %d, %d, %d\n", a, b, c );
a = 2*a + b+c;
b = 12;
// if(a<800) _sumab(a, b, c);
printf("3: %d, %d, %d\n", a, b, c );
}

void sumab(int a, int b, int c)
{
printf("1: %d, %d, %d\n", a, b, c );
_sumab(a, b, c);
a = a*4;
printf("4: %d, %d, %d\n", a, b, c);
}


int main()
{
int out1 = 0;
int out2 = 1;
int out3 = 2;
sumab(out1+100, out2, out3);
printf("5: %d, %d, %d\n", out1, out2, out3);
return 0; 
}

在前一个代码中,在调用子函数之后,buf中存储的值即使在main函数中也会发生变化。但是在后面的代码中,在调用子函数之后,a, b, c的值保持不变,就像它们在主函数范围中一样。为什么呢?

我是否遗漏了一些重要问题?就地如何发生?

如果fft(buf, 8)表示计算buf的傅立叶变换并将其保存在buf中,表达式fft(buf+2, 8)怎么样,它将计算{的傅立叶变换{1}},但存储在哪里?

提前致谢。

1 个答案:

答案 0 :(得分:4)

您的问题的关键是在C中,您无法将数组传递给函数

当你这样写:

void fft(cplx buf[], int n)

根据C11标准§6.7.6.3p7中定义的规则,该声明中的类型为调整 * (引用最新的公共草案,n1570,在这里):

  

参数声明为'' type ''的数组应调整为''限定指针    type '',其中类型限定符(如果有)是在[]内指定的类型限定符。   数组类型推导。 [...]

这意味着,真正的声明如下:

void fft(cplx *buf, int n)

所以,你实际上是在传递一个指针,并且该函数可以通过该指针操作原始数组。

*)通常说数组衰减为指针。这不是该标准的官方措辞,但是被广泛理解。如果您有这样的数组:

char a[5];

并且您只需编写a,这被评估为指向a类型char *的第一个元素的指针。因此,使用如下声明的函数:

void foo(char x[]);

你可以称之为

foo(a);

真正传递的是指向a的第一个元素的指针,因此,a“衰减”为指针。