在C语言中使用函数改变数组?

15
我想调用一个函数,并且希望该函数将程序中字符串或数组的内容更改为常量。

伪代码:

some_array = "hello"
print some_array   #prints "hello"
changeArray(some_array)
print some_array  #prints "bingo"

我知道我必须将指针传递给那个函数。这是我写的代码,

void changeArray(char *arr){
    arr = "bingo";
}

int main(int argc, const char* argv[]){
    char *blah = "hello";
    printf("Array is %s\n",blah);
    changeArray(blah);
    printf("Array is %s\n",blah);
    return EXIT_SUCCESS;
}

我该怎么做?

3个回答

34
您传递的是数组指针的值而非引用。正确的写法应该是:
void changeArray(char **arr){
    *arr = "bingo";
}

int main(int argc, const char* argv[]){
    char *blah = "hello";
    printf("Array is %s\n",blah);
    changeArray(&blah);
    printf("Array is %s\n",blah);
    return EXIT_SUCCESS;
}

你将地址“hello”传递给了函数changeArray,但是在函数中你改变的是传递的值而不是原始指针。我所做的更改是传递指针的地址,并在函数中更改指针本身。
请注意,char *blah = "hello";定义了一个指向常量字符串的指针,以及*arr = "bingo";,这都是可以的,但如果你考虑更改字符串本身,你将无法实现。
编辑:当你将参数(即使是指针)传递给函数时,实际上是将其复制到函数从那里读取它的某个地方(通常是堆栈)。你传递的不是参数本身,而是它的副本。当函数修改它时(如在arr = "bingo";中),它修改的是变量的副本,而不是原始变量。因此,为了更改变量本身,我们将变量的地址传递给函数(changeArray(&blah); - &表示地址),并且在函数中,我们修改存储在我们传递的地址中的变量(*arr = "bingo"; - *表示地址arr中的变量)。
假设原始的blah指针位于地址0x00000000,并包含例如0x00000010的"hello"字符串的地址。如果你将blah传递给函数,那么你将其复制到一个新变量arr中,该变量位于地址0x00000020(例如)。
Variable    Address     content
-------------------------------
blah       00000000    00000010   (points to hello)
"hello"    00000010    "hello" (this is just an example, so don't be hard on me :) )
arr        00000020    00000010
"bingo"    00000030    "bingo" (and again...)

现在,如果您更改arr的内容,则会更改地址0x00000020中的值,但不会更改地址0x00000000中的值,因此blah仍然包含00000010。
Variable    Address     content
-------------------------------
blah       00000000    00000010   (points to hello)
"hello"    00000010    "hello" (this is just an example, so don't be hard on me :) )
arr        00000020    00000030 (points to "bingo")
"bingo"    00000030    "bingo" (and again...)

我们所做的是将blah的地址0x00000000复制到arr中,在函数中,我们说:“arr的内容是一个地址,前往此地址并更改其内容以指向“bingo”字符串”。因此,现在地址0x00000000中的内容(即blah)指向“bingo”。

Variable    Address     content
-------------------------------
blah       00000000    00000030   (points to "bingo")
"hello"    00000010    "hello"    (this is just an example, so don't be hard on me :) )
arr        00000020    00000000   (points to `blah`)
"bingo"    00000030    "bingo"    (and again...)

希望我没有让您困惑...

这段话与IT技术无关。

1
请务必重新措辞您的答案。在C语言中,数组始终通过引用传递。如果原帖想要更改数组的内容,应该更改每个位置上的元素。对于字符数组(字符串),原帖应该使用strcpy()或其他字符串函数。 - André Caron
6
这是一种误导性的看法。在 C 语言中,数组从未被传递到函数内或从函数中传出。所有看起来像接收数组的函数实际上都接收指针,而且声明一个返回数组的函数是不合法的。在 C 语言中,所有参数(包括指针)都是按值传递到函数中的。C 语言是一种"按值传递"的语言。 - CB Bailey
1
@André,你是错误的;C只按值传递。用作rvalue的数组会隐式转换为指向其第一个元素的指针。当rvalue作为参数传递给函数时,指针按值传递。所有这些都在C标准中明确而清楚地说明;我敦促你阅读它。如果OP使用strcpy,那么将导致未定义的行为(并且在大多数实现中会崩溃并出现内存保护违规),因为blah指向一个字符串常量,不能写入。 - Jim Balter
@MByD 为什么你不需要使用 strcpy - cokedude
@cokedude 因为 "bingo" 是一个字符串字面量,它在函数的上下文之外也是有效的,所以你可以从任何地方引用它,因此你只需要一个指向它的指针,而不是它的副本。 - MByD
显示剩余4条评论

7

你的代码中没有数组。如果你想要修改指向 blah 字符指针的指针,那么你需要将一个指向指针的指针传递到函数中。 然而,如果你想使用数组来实现这个功能,那么你需要像下面这样做:

void changeArray(char arr[]) {
  // or you can use char *arr, it's the same thing from
  // the C compiler's point of view
  strcpy(arr, "blah");
  // alternatively, you could set each element. i.e. arr[0] = 'b';
}

int main (int argc, char** argv) {
  char blah[100] = "hello"; // this is an array
  printf("Array is %s\n", blah);
  changeArray(blah);   // array decays to pointer
  printf("Array is %s\n", blah);
  return EXIT_SUCCESS;
}

谢谢,使用strcpy()很好。我有一个任务需要完成,但在change函数中无法使用**arr作为参数,所以这很完美。 - andrewb
1
@Ferruccio为什么在changeArray(blah)中不需要使用&符号? - cokedude
3
在C语言中,实际上无法将数组作为参数传递给函数。数组会“衰变”为指向数组第一个元素的指针,因此调用changeArray(blah)changeArray(&blah[0])相同。由于该函数声明为void changeArray(char arr[]),该声明与changeArray(char* arr)相同,因此调用与函数签名匹配。 - Ferruccio
值得注意的是,该数组有100个位置,以确保字符不会溢出到堆栈中的另一个位置。之前我们没有这样做,因为在C语言中,当你将一些字符串赋值给指针时,实际上是将指针指向代码段而不是内存堆栈。 - TheLogicGuy
就我个人而言,我总是使用数组来编写代码,例如void changeArray(char *arr),但是在我现在使用的这个IDE上却行不通。我不得不使用你所用的表示法。我在想这是否是编译器/IDE设置中的一个错误。 - netskink

0

你需要传递一个指向数组的指针而不是数组本身。

另外一件事:在你的函数中添加一个控制条件。想一想:如果“bingo”比strlen(some_array)更大会发生什么?这将会给你一个错误,因为在C语言中,如果你需要动态数组大小,你必须malloc它!


1
这是不正确的,他并没有复制字符串,而是将指针指向了新的字符串。这段代码示例中不需要分配内存。 - MByD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接