我是C的新手,我有疑问。
由于C函数创建了它的参数的本地副本,我想知道为什么以下代码按预期工作:
void function(int array[]){
array[0] = 4;
array[1] = 5;
array[2] = 6;
}
int main(){
int array[] = {1,2,3};
function(array);
printf("%d %d %d",array[0],array[1],array[2]);
return 0;
}
线路输出为4 5 6。
为什么这样做有效,而以下情况却没有?
void function(int integer){
integer = 2;
}
int main(){
int integer = 1;
function(integer);
printf("%d",integer);
return 0;
}
在这种情况下,输出只有1。
简短版本:为什么函数可以修改父变量的值,如果它们作为数组传递?
谢谢大家!
答案 0 :(得分:19)
这是因为数组倾向于衰减为指针。
int a[] = { 1, 2, 3 };
int* p = a; // valid: p is now the address of a[0]
a = p; // NOT valid.
printf("a = %p\n", a);
printf("p = %p\n", p); // prints same address as a
a
和p
将打印相同的值。
与其他人所说的相反,a
不是一个指针,它可以简单地衰减为一个。 http://c-faq.com/aryptr/aryptrequiv.html
在你的第一个function()
传递的内容是数组第一个元素的地址,函数体取消引用它。事实上,编译器正在将函数原型视为:
void function(int* array /*you wrote int array[]*/){
array[0] = 4;
array[1] = 5;
array[2] = 6;
}
function(&array[0]);
这必须发生,因为你说的是“未知大小的数组”(int array [])。编译器无法保证推导出值传递所需的堆栈量,因此它会衰减为指针。
----编辑----
让我们结合你的例子,并使用更多与众不同的名字,使事情更清晰。
#include <stdio.h>
void func1(int dynArray[]) {
printf("func1: dynArray = %p, &dynArray[0] = %p, dynArray[0] = %d\n",
dynArray, &dynArray[0], dynArray[0]);
}
void func2(int* intPtr) {
printf("func2: intPtr = %p, &intPtr[0] = %p, intPtr[0] = %d\n",
intPtr, &intPtr[0], intPtr[0]);
}
void func3(int intVal) {
printf("func3: intVal = %d, &intValue = %p\n",
intVal, &intVal);
}
int main() {
int mainArray[3] = { 1, 2, 3 };
int mainInt = 10;
printf("mainArray = %p, &mainArray[0] = %p, mainArray[0] = %d\n",
mainArray, &mainArray, mainArray[0]);
func1(mainArray);
func2(mainArray);
printf("mainInt = %d, &mainInt = %p\n",
mainInt, &mainInt);
func3(mainInt);
return 0;
}
在ideone上进行现场演示:http://ideone.com/P8C1f4
mainArray = 0xbf806ad4, &mainArray[0] = 0xbf806ad4, mainArray[0] = 1
func1: dynArray = 0xbf806ad4, &dynArray[0] = 0xbf806ad4, dynArray[0] = 1
func2: intPtr = 0xbf806ad4, &intPtr[0] = 0xbf806ad4, intPtr[0] = 1
mainInt = 10, &mainInt = 0xbf806acc
func3: intVal = 10, &intValue = 0xbf806ad0
在func1
和func2
中,“dynArray”和“intPtr”是局部变量,但它们是指针变量,它们从main接收“mainArray”的地址。
此行为特定于数组。如果您要将数组放在结构中,那么您可以按值传递它。
答案 1 :(得分:3)
传递给函数的数组将转换为指针。将指针作为参数传递给函数时,只需在内存中提供变量的地址即可。因此,当您修改数组单元格的值时,可以编辑赋予函数的地址下的值。
当你将一个简单的整数传递给一个函数时,整数被复制到堆栈中,当你修改函数中的整数时,你修改了整数的副本,而不是原始的。
在C中,我们可以使用三种类型的内存:
如果这个数组由一个函数传递,它是一个指针(另一个变量的地址),它存储在堆栈中,当我们调用该函数时,我们将指针复制到堆栈中。
在整数的情况下,它也存储在堆栈中,当我们调用函数时,我们复制整数。
如果我们想修改整数,我们可以传递整数的地址来修改指针下的值,如下所示:
void function(int *integer)
{
*integer = 2;
}
int main()
{
int integer = 1;
function(&integer);
printf("%d", integer);
return 0;
}
答案 2 :(得分:1)
'按参考传递'和'按值传递'
之间存在差异通过引用传递到内存中的位置,其中pass by value直接传递值,数组变量始终是refference,因此它指向内存中的某个位置。默认情况下,整数将按值传递
答案 3 :(得分:1)
在第一个代码中,您传递的数组的地址指向数组中的顶部元素。因此,当您修改函数中的值并返回到main函数时,您仍然访问位于同一地址的同一个数组。这称为通过引用传递。
但是,在第二种情况下,整数的值从main函数复制到被调用函数。换句话说,两个整数在存储器中处于不同的地址。所以修改一个不会修改另一个。
答案 4 :(得分:0)
数组名称是指向数组中第一个元素的指针。在第一个代码示例中,您已经传递了一个指向包含第一个数组元素的内存位置的指针。在第二个代码示例中,您按值传递了一个整数,因此它与名为“integer”的局部变量无关
检查该链接
通过引用传递并按值传递