谁来解释下 c 语言的传值?

刚开始学。在 android 上利用垃圾时间看完过一本速成小册子作为骨架,现在在看 the C Programming Language 填血肉。代码勉强能懂(所以你可以辅以代码),比如

typedef struct _FcitxConfigColor {
    double r;
    double g;
    double b;
} FcitxConfigColor 

这个难度的代码是懂的。

就是对背后的思想不了解(我没学过微机嵌入式硬件汇编算法那些),很好奇为什么一定要用指针才能写入变量地址,函数参数直接用变量似乎是 copy 值然后地址不对的。

不难吧?求浅显易懂!

typedef 不是类型定义吗?你说的指针代码是哪些?
把不好懂的指针代码列出来看看。

C 对硬件的操控比较强大。指针可以被看作是存储变量地址的一个变量。如果说错了,球纠正。

个人理解是 C 里的变量存的都是值,只是指针变量存的值是其他变量的地址。
使用 & 获得变量地址,* 获得指针变量所存的地址的变量的值。

int a=5;
int *p;
p=&a;
printf("p=%d
*p=%d",p,*p);

赋值时,不允许普通变量的值直接赋为地址,而只是引用值,1. 可以保证地址不会被随意修改(就是指针不会乱指),

0p=p+1; printf("p=%d *p=%d",p,*p);
2. 同时保证该地址所存的值不会被随意修改。

0*p=*p+1; printf("a=%d *p=%d",a,*p);

你理解的没错。
C 函数的参数传递本质上是按值进行传递。如果你传递变量,则会把变量的值拷贝给形参; 如果你传递指针(变量的地址),则会把变量的地址这个值拷贝给形参。
在函数内部,对形参的操作,是不会影响实参的。举例来说,当你传递了指针(变量的地址),实参是某变量的地址,形参也是某变量的地址,你可以对该地址进行操作,甚至修改存储在该地址的内容(也就是改变某变量的值),但是你改变不了实参。
至于为什么要这么设计,很明显,这样可以有效的保护实参,降低实参被意外修改的概率。

设计意图貌似还包括可以更好的控制存储器的使用

设计意图貌似还包括可以更好的控制存储器的使用
这是指针的设计意图,不能算作函数调用时形参传递规则的设计意图吧?

设计意图貌似还包括可以更好的控制存储器的使用
这是指针的设计意图,不能算作函数调用时形参传递规则的设计意图吧?
好吧我在说指针。。。

C 函数传递参数时,如果只是引用实参的值而不需要改变实参的值,直接传值就行了,如果在函数中需要改变实参的值时,就必须传地址才行,用指针去修改所指向的值。像 bruce 兄说的那样,函数实参传递给形参时,其实是对实参的一个拷贝,所以在函数中修改行参的值是不会影响实参的。但是用指针可以修改其指向的地址中的值。同样如果实参是一个指针的话,如果想要在函数中修改这个指针的值时,则需要传递一个二维指针进去。。

额,这个问题一句半句说 :nauseated_face: 不清。我的经验指针的概念没有难度,难在用。什么指针数组数组指针,函数指针指针函数,结构指针指针结构。传值方面用指针传递的是实参。一个很常见的例子。printf 函数和 scanf 函数的参数其实都是指针。scanf 不说了,它的参数要带取址符。printf 函数中字符串加了引号就是一个指针了,是指向字符串开头那个字符的指针。举个例子。
#include <studio.h>

void do_it(char :nauseated_face: *);

int main(void)
{
do_it(“I love openSUSE.”)
return 0;
}

void do_it(char* ch)
{
printf(ch);
}

俺也是自学的 c 语言。走了不少弯路,就学习给点建议吧。要看好书,特别初学容易被误导,不过 the C Programming Language 还是不适合初学填血肉的吧。首先它不是标准 c,它写得好也只有内行看得出,太精炼了。可以看看《c 和指针》填血肉,讲得很细,且突出指针。在用《c 语言解惑》和《c 语言的陷阱与缺陷》打实基础。两本很薄的小册子。虽然这三本也不是用最新的 c99
但比较接近了。 the C Programming Language 留到最后去看吧。

写得不好或有错欢迎批评。

不好意思。。。在手机上发的贴。。。那几个表情是误点。。。。

如果实参很大的话,需要用指针来节省栈空间。同时避免值拷贝带来的性能浪费。

恩~学习了,感谢 :slight_smile:

参数小时可以保存到寄存器中,大了只能往栈里压。

个人感觉

  1. side effect 和 return value

C 里面,

比如:

i=3
j=++i

一条表达式会有一个 return value,是这条表达式的「值」(上面不止一条语句)。同时,执行这条表达式还可能会对输出输入设备,变量,各种外部的环境产生影响。比如上面这里的 ++i 的 return value 是 4, side effect 是让变量 i 的值加一。

调用一个表达式有两个目的:为了得到 return value,为了产生 side effect 。

ex1. 考虑 i++ 这个表达式里面的 return value 和 side effect

  1. pass by value 和 pass by reference

C 只有 pass by value 的方式来传参数。换句话说,我们不能从函数内部改变一个变量的值。

但我们就是要这样做,怎么办呢?两个思路,将改变的值作为 return value 返回然后重新赋值 x=f(x) 。另一个是思路是在 side effect 上面动脑筋。

传指针就是这种目的:传入变量的地址,然后函数内部通过这个地址,我们有个 * 操作符,可以通过 *ptr 来修改对应的内存空间,利用 side effect 来改变这个值。

void f(int *x){
   // the value of x is a address
   (*x) = 1; //   *x is just the place holds the value 
}
f(&abc);

因为 *&x ===> x ,「碰巧」就可以修改 x 的值

ex2. 为何 scanf("%d%d%s", &a, &b, c); ,a 和 b 要 &,但 c 不需要?为何 printf 总是不需要& 的?

楼上都是大牛、、、膜拜下、、、

C 语言函数传递参数分两种:传值和传址、、、

传值是最好理解的,就是把原来变量的内容复制一份给函数的参数,传址是传个复制品,你改变复制品不改变愿品的值、、、就像你去网上下载一份文档,你就是怎么编辑这份文档,服务器上的还是哪些内容,你再次下载的话,文档的内容是不变的,给你编辑没关系、、、

传址需要理解指针了,指针号称是 C 语言的灵魂,传址是把变量再哪儿存着告诉形参,在函数中编辑参数所指向的地址,就是编译原来的变量。(不懂指针很晕的)、、、举个例子,还是服务器文档,就像你这个参数存的不是文档,而是文档的 url,你用编辑器打开 url,编辑器自动打开的是服务器里的文档(好像这个我还不知道那个编译器支持,比喻而已),你再编辑文档的时候,就是编辑服务器的文档、、、你编辑玩,再去下载,下载出来的就是你编辑过的文档、、、

C++ 还有一种传递参数的方法:引用。引用传址也可以改变原参数的值,引用可以理解为一个别名,等于你直接把参数交给函数处理、、你改变引用的值也就改变原参数的值、、、这个就像本来就一件东西,在我这里叫 a,你(函数)要拿去用,你叫他 B,你用过了,再还给我(调用函数的),你把里面内容改变了,还我的时候也改变了、、、

Java 的比价坑爹、、、至少我比较喜欢 C++ 的这样认为、、、Java 文档说的是全部传值、、但是在自定义类生成的对象中,又是引用、、java 完全废除了指针,在 C++ 中对象在栈中和堆中都可以分配,java 中只能在堆中分配的、、、

C# 支持传值和引用,C# 中还有个 out 关键字很好用,这个是在函数中为参数复制,相当于可以有返回值、、、、

主题上定义个结构体何意?

c 准确来说只有传值,传址说到底还是传值。
另外 c++11 还增加了右值引用,用于 Move Constructor 等等。