指针是c语言的一个特色。
1 将地址形象的比喻为指针。
2 访问的两种形式:1 直接访问:比如定义了变量a,然后通过变量名a直接访问
2 间接访问:定义a,得知a的地址,由于地址指向变量,所以可以直接 访问。
3 除了整型,实型,字符型,还有一种是存放地址的变量。Int * a;a= &p;
4 一个变量的地址我们称之为指针;一个存放别的变量地址的变量叫做指针变量;指针变量的值就是指针(即地址);如果存放的指针指向的数据是整形,则我们说这个指针变量是指向整形变量的指针变量。
<重中之重>指针变量:1 程序中两处 * :声明与使用。
声明: * 指示后面的变量是指针变量,且其基类型是前面的类型。
使用: * 运算符,把地址转向所指向的变量。
2可以在定义时同时对他进行初始化。
3 必须指定基类型:因为他指代的数据类型有可能是int long 等等,而在后续要进行指针的加减,指针加一,如果是int 则增加2或4个字节,如果是long,则8个字节。所以一定要指定。
4 赋给指针的变量一定是地址,而不能是其他数据类型。
5 给指针变量赋值:1直接赋值 p=&a;
2 引用赋值 如果*p=1;之前必须p=&a;否则会因为不知道地址而有可能会占用有用的地址。
6 注意指针变量也是一个变量,所以在指针变量的范畴内,各种变量的赋值都可以,就和变量一样,而和普通变量交互,则需要有地址,有基变量。
<第一个重点>
重重重重:1 单向的值传递:即实参传递过去的形参,之后是形参来回变换,与实参无关。2 由于地址本身就存在,不存在什么变化,所以,只能够通过地址指向的值来回改变。
指针可以作为函数参数
要点:1(单向的值传递) 所有都要与之结合。
要点:2(址变换) 3(*址变换) 4(值变换)只有4不可以改变原值
重点:不可能通过调用函数来改变实参指针变量的值,但是可以实参指针变量所指向的值。
函数的参数不仅可以是整形,实数型,字符型,数组型,也可以是指针型。
他的目的是址传递。
<A>我们的问题是如何使原值改变。函数参数传值,传完之后回来,看是否原值改变。
以两个数要变换为例。
首先采用(值传递),由于是单向传递,况且要想改变原数据,必须要从指针(地址)这方面下手,所以,即不可以改变原值;
然后是(址传递),由于传过来之后,实参要赋给形参,而此时在变换函数(swap)形参来回变换,也就是实参不变换,而形参变换,所以没用,且是单向的。所以不能改变原值。
然后是(*地址)传递,自己画图,实参传过来之后,由于虽然还是改变形参,但是改变的是形参上对应的数字,即改变原地址上对应的数字,即可以改变原值。
<误区> 就是说以前虽然是值传递,但是值传递回来return之后赋给了新的变量,既然是新的变量,所以输出了之后肯定是改变数据的,这就是产生错觉的原因。
总结难点:1 单向的值传递:即实参传递过去的形参,之后是形参来回变换,与实参无关。2 由于地址本身就存在,不存在什么变化,所以,只能够通过地址指向的值来回改变。
<第二个重点>:通过指针引用数组。
1 数组元素的指针就是数组元素的地址。
2 引用数组可以用下表法,也可以用指针法。
重:3 数组名(不包括形参的数组名)可以与首元素地址等价。即 int * p;p=a或p=&a[0];
重:4 指针法 *(a+i) *(p+i);这两者都是指向a[i];
5 指针运算:
1 首先指针运算的p++不是简单地加一,而是根据变量类型的字节数去加一。如果是int 则可能是+2 或+4,如果是float,则是+4;
2 可以使用p++,因为他是变量,而不能使用a++,因为a是常量。
重:注意p+i与a+i的区别,a+i是自身的地址直接加字节数,而p+i是把地址赋给另一个指针变量去进行加减。
6 写程序时要注意此时指针的位置,因为就算超出,他实际上也不会报错。
7 也可以使用p[i],但是注意此时一定要知道当前p在什么位置,如果一开始P指向a[2],则p[3]则是a[5],所以不建议使用这种方式.
8 <重中之重>:用数组名做函数参数:
1 形参数组的值发生变化,实参也发生变化(注意:形参的值指的是指针的值而不是地址【上一节指针做参数的三种情况】)
重:2 void f(int arr[],int n)=====等价于void f(int * arr,int n);
3 指针变量在visual c++里占据4个字节。
4 实参数组名是一个常量,而形参数组名是一个变量,所以可以赋值,而常量不可以赋值即a=a+3(a是常量),不能使用,而(arr=arr+3)是可以的;
<第三个重点>:通过指针引用字符串
1 表示字符串的两种方法:1 用字符数组2 用指针指向字符串的字符。
2 指针法:char * string=”I love china”; printf(“%s”,string);
3 不能够重新赋值,因为字符常量是不能改变的。
重:4 实际上是把字符串的第一个字符的地址赋给指针变量,然后输出会自加(这就是不用遍历的原因),最后遇到\0会停止(这才是可以自加的真正原因吧,因为可以自动停止)。
重:5 为什么输出地址就可以输出字符?数组就需要*?
应该是编译器的处理,因为字符数组即char a[]遍历就需要*a.
6 输出的时候还是用字符数组。
<重中之重>:
1 传递参数可以用数组名,即地址,也可以用指针。
重:2 字符数组除了比数字数组多了一种方法,首先他俩同时都可以传递数组名和数组首地址,当然首地址是用另一个变量,并且由于他还可以这么定义char * string=”i love china”;所以还可以直接把string传递,其实本质是一样的,都是地址,只不过编译器对他进行了优化(遍历,不用加*),所以其实都是一样的。
实参形参的数组名与指针?
3 最后要自己加上\0;
4 最后就是写法问题???
重:5作为实参,可以用数组名(不带中括号),可以用char * p(其中p=a或&a[0]),即变量;还可以用char * string=”aaaaaa”,直接把string传入。当然,前两种就是和数字数组是一样的。即字符数组和数字数组基本上是一样的,只不过多了一种写法。
作为形参,本可以用数组名和指针变量,但是不知道为啥数组名行不通,暂且就是指针变量把。
6 字符数组可以再赋值,字符指针变量不可以。
重重重重:都是地址(基本上是一个,数组则是首地址)的传入传出,所以可以对原值改变。
重重重重:当想改变原值的时候,比如int a;在改变值的函数内部,一定要赋值,
举个例子:#include<stdio.h>
int main(){
void change(int * m);
int a=10;
int *p;
p=&a;
change(p);
printf("%d",a);
return 0;
}
void change(int * m){
* m=* m+1;//注:这里一定要给*m赋值,之前的错误是只有*m+1,而没有赋值,结果当然不会改变。
}
重重重重:字符型实参传递参数的形式:1 数组名 2 数组首地址 3 string 注:前两种形式都是字符数组,最后一种是指针型字符数组。
字符型形参应该是 1 * ,2 m[]注:两种都行,但是现在给第一种赋值遇到一些问题。
附代码:#include<stdio.h>
int main()
{
void change(char * m);
char * string="Ia love China";
char a[19]="I love china";
//change(&a[0]);
change(string);
//传递参数的形式:1 数组名 2 数组首地址 3 string 注:前两种形式都是字符数组,最后一种是指针型字符数组
//change(string);
printf("%s\n",a);
return 0;
}
void change(char * m){
//形参应该是 1 * ,2 m[]注:两种都行,但是现在给第一种赋值遇到一些问题。
*m='u';//这里现在遇到一些问题。
}