避免 C 语言的副作用

big*_*zer 1 c arrays state functional-programming side-effects

这个问题特别适用于数组。

在许多语言中,我会这样做:

    #This is in python for simplicity:

    def increment(mylist):
        for i in mylist:
            i += 1;
            
        return mylist
    

    mylist = {0,1,2,3}
    mylist = increment(mylist)
Run Code Online (Sandbox Code Playgroud)

我尝试了几种在 C 中返回数组的方法,但没有一个像上面那样工作。看起来 C 根本就不打算以这种方式工作。相反,我必须这样做:

#include <stdio.h>

increment(int *myarray, int size) {
    for(int i = 0; i < size; i++){
        myarray[i] += 1;
        
    }
}

int main(){
    int myarray[4] = {0,1,2,3};
    increment(myarray, 4);

}
Run Code Online (Sandbox Code Playgroud)

不用说,C 函数会更改数组的状态,因此是一个副作用函数。有充分的理由避免这种情况(这不是这个问题的主题)。

C 有没有办法避免这些类型的副作用?

Ser*_*sta 7

请注意,在 python 中,对象是通过引用传递的。

def increment(mylist):
    // mylist is a local reference to the original array
    for i in mylist:
        i += 1;   // i is a local value: nothing is changed in mylist!
        
    return mylist  // returns a reference to the original (and unchanged...) array
Run Code Online (Sandbox Code Playgroud)

改变原始列表应该做什么:

def increment(mylist):
    for i in range(len(mylist)):
        mylist[i] += 1
    // returning mylist is optional since the caller's list has been modified
Run Code Online (Sandbox Code Playgroud)

这与 C 中的完全相同

int *increment(int array[], int size) {
    for (int i=0; i<size; ++i) {
        array[i] += 1;
    }
    return array;
}
Run Code Online (Sandbox Code Playgroud)

但你可以用 Python 构建并返回一个全新的列表:

def increment(mylist):
    return [i + 1 for i in mylist]
Run Code Online (Sandbox Code Playgroud)

这在 C 中无法轻松完成。惯用的方法是让调用者提供数组和大小(如上所述)或返回动态分配的数组:

int *increment(int array[], int size) {
    int *new_array = malloc(size * sizeof(int));
    for (int i=0; i<size; ++i) {
        new_array[i] = array[i] + 1;
    }
    return new_array;
}
Run Code Online (Sandbox Code Playgroud)

并让调用者在完成转移所有权后释放返回的数组。