变量实质
声明两个变量,其中整形变量i占两个字节,字符型a占一个字节。
int i;
char a;
实际在内存中的映像如图
变量赋值
赋值给变量,即是将该值赋给相应的地址中
i=30;
a='t';
如此,我们可以通过代码打印查看变量与它的地址
#include<stdio.h>
int main ()
{
int i = 39;
printf ("%d\n" , i);/*i*/
printf ("%d\n", &i) ;/*i的地址*/
return(0) ;
}
指针
声明指针变量pi
int *pi;
则内存映射为
可以看出pi不过是在内存的某个地方声明一个一定宽度的内存空间。
将变量i的地址编号赋给pi指针
pi=&i;//i的地址为6、7
现在的情况就是:i是一个变量,pi指向了变量i,pi是i变量的地址编号相当于&i,而*pi则是读取i的存储的地址的值。
使用代码打印进行对比
#include<stdio.h>
int main ()
{
int i = 39;
int *pi;
pi=&i;//i的地址为6、7
printf ("--值--\n", &i) ;
printf ("%d\n" , i);/*i*/
printf ("%d\n", *pi) ;
printf ("--地址--\n", &i) ;
printf ("%d\n", &i) ;/*i的地址*/
printf ("%d\n", pi) ;
return(0) ;
}
所以我们可以通过改变指针pi来改变所指的地址内的变量值。
char a , *pa;
a=10;
pa = &a;
*pa = 20;
通过数组名访问数组元素
使用数组名(首地址)和普通方式访问数组元素,效果一致
#include<stdio.h>
int main ()
{
int i, a[] = { 3,4,5,6,7,3,7,4,4,6};
for (i = 0; i <=9; i++)
printf("%d\n", * (a+i) );
printf("--数组元素--\n");
for (i = 0; i <=9; i++)
printf("%d\n", a[i] );
return(0) ;
}
字符串数组
#include<stdio.h>
void to(char *array)
{
for(int i=0;*(array+i)!=0;i++)
{
if(*(array+i)==0)
{
break;
}
else
{
printf("%c",*(array+i));
}
}
printf("\n");
}
main()
{
char str[] = { "afsdfsdfdf\O"};/*待查找的字符串 */
to(str);/*调用函数以实现所要操作。*/
printf("%s\n",str);
return(0);
}
通过指针访问数组元素
#include<stdio.h>
int main ()
{
int i, *pa,a[] = { 3,4,5,6,7,3,7,4,4,6};
pa=a;
for (i = 0; i <=9; i++)
printf("%d\n", pa[i] );
printf("--赋值数组名--\n");
for (i = 0; i <=9; i++)
printf("%d\n",*(pa+i) );
return(0) ;
}
数组名与指针变量的区别
数组名与指针变量还是有所区别的,数组名只是一个指针常量,而指针是指针变量。
#include<stdio.h>
int main ()
{
int i,*pa,a[]= {3,4,5,6,7,3,7,4,4,6};
pa =a;
for (i = 0; i <=9; i++)
{
printf("%d\n",*pa);
pa++;/*注意这里,指针值被修改*/
}
return(0) ;
}
上述代码中,pa换成a是无法正常编译的
const int i
const声明定义的称为符号常量,后期不能进行修改其值。有两种写法:
const int ic = 20;//等同于
int const ic = 20;
const定义的*pi是不可修改的,但是pi是可以修改的
#include<stdio.h>
int main ()
{
int il = 30;
int i2 = 40;
const int *pi = &il;
pi = &i2;/*注意这里,pi可以在任意时候重新赋值一个新内存地址*/
i2 = 80;/*想想看:这里能用*pi = 80来代替吗?当然不能!*/
printf("%d\n",*pi);
return(0);
}
int *const pi与int const *pi
int *const pi,可以改变*pi,不能改变pi
int const *pi,可以改变pi,不能改变*pi
#include<stdio.h>
int main ()
{
int il = 30;
int i2 =40;
int *const pi = &il;
/* 不能pi = &i2;即不能再指向另一个新地址。*/
il = 80;/*可以用*pi = 80;来代替,可以通过*pi修改i1的值。*/
printf("%d",*pi);/*输出是80*/
return(0);
}
声明为常量的pi,将无法通过其他方式进行修改,定义其他指针变量去改对应地址的值也行不通。
函数参数传递
第一种:值传递
#include<stdio.h>
void Exchg1 (int x, int y)
{
int tmp;
tmp =x;
x = y;
y = tmp;
printf ("x = %d,y = %d\n",x, y);
}
main()
{
int a = 4,b= 6;
Exchg1(a, b);
printf("a = %d, b = %d\n", a, b);
return(0);
}
这是因为函数形参实参之间传递的是:
int x=a;
int y=b;
仅仅是将a、b的值赋给x、y,并没有对a、b进行本质上的改变。
第二种:地址传递
#include<stdio.h>
void Exchg2 (int *px, int *py)
{
int tmp = *px;
*px = *py;
*py = tmp;
printf ("*px= %d,*py = %d\n",*px,*py);
}
main()
{
int a = 4,b= 6;
Exchg2(&a, &b);
printf("a = %d, b = %d\n", a, b);
return(0);
}
int *px=&a;
int *py=&b;
这样,就使得px、py两个指针变量指向了a和b地址,而通过修改他们的值,就能够修改a和b的值了。
第三种:引用传递
#include<stdio.h>
void Exchg3 (int &x, int &y)
{
int tmp = x;
x = y;
y = tmp;
printf ("x= %d,y = %d.\n",x,y);
}
main()
{
int a = 4,b= 6;
Exchg3(a, b);
printf("a = %d, b = %d\n", a, b);
return(0);
}
int &x=a;
int &y=b;
这样就代表,x、y直接引用了a、b变量,也就是直接当做实参本身来使用了。
指针的指针
short int i;
char a;
short int * pi;
a = 7;
i = 50;
pi = &i;
short int **ppi; /* 这是一个指向指针的指针,注意有两个“*”号*/
*ppi = π
所以,ppi=pi的地址,9。*ppi=5,**ppi=50。
指针的指针实例代码
(1)设计一个函数: void find1(char array[],char search,char *pa)
要求:这个函数参数中的数组array是以О值为结束的字符串,要求在字符串array 中查找字符是参数search里的字符。如果找到,函数通过第三个参数(pa)返回值为array字符串中第一个找到的字符的地址。如果没找到,则为pa为0。
#include<stdio.h>
void find1 (char array[], char search,char *pa)
{
int i;
for (i= 0;* (array + i)!= 0;i++)
{
if(* (array+i)== search)
{
pa=array + i ;
break;
}
}
}
main()
{
char str[] = { "afsdfsdfdf\O"};/*待查找的字符串 */
char a = 'd' ;/*设置要查找的字符*/
char *p = 0;/* 如果查找到后指针p将指向字符串中查找到
的第1个字符的地址。*/
find1(str, a, p);/*调用函数以实现所要操作。*/
if(0 == p)
{
printf("没找到!\n");/*如果没找到则输出此句*/
}
else
{
printf("找到了,p = %d", p);/*如果找到则输出此句*/
}
return(0);
}
此处,仍然是使用值传递的方式,pa=p,所以不会使p发生改变。
正确的应该是这样写
#include<stdio.h>
void find1 (char array[], char search,char **ppa)
{
int i;
for (i= 0;* (array + i)!= 0;i++)
{
if(* (array+i)== search)
{
*ppa=array + i ;
break;
}
else if(* (array+i)==0)
{
*ppa = 0;
break;
}
}
}
main()
{
char str[] = { "afsdfsdfdf\O"};/*待查找的字符串 */
char a = 'd' ;/*设置要查找的字符*/
char *p = 0;/* 如果查找到后指针p将指向字符串中查找到
的第1个字符的地址。*/
find1(str, a, &p);/*调用函数以实现所要操作。*/
if(0 == p)
{
printf("没找到! n");/*如果没找到则输出此句*/
}
else
{
printf("找到了,p = %d", p);/*如果找到则输出此句*/
}
return(0);
}
函数名与函数指针
示例函数指针声明方法
void (*FunP)(int);
n种函数调用方法
#include<stdio.h>
void MyFun (int x);/*这个声明也可写成: void MyFun( int )*/
void (*FunP)(int);/*也可声明成void(*FunP)(int x),但习惯上一般不这样。*/
int main (int argc, char *argv[ ])
{
MyFun (10);/*这是直接调用Myun函数*/
FunP =&MyFun;/*将MyFun函数的地址赋给FunP变量*/
//FunP = MyFun; /*将MyFun函数的地址赋给FunP变量 */
//(*MyFun)(10);
(*FunP)(20);/*这是通过函数指针变量FunP来调用MyFun函数的。*/
}
void MyFun (int x)/*这里定义一个MyFun函数*/
{
printf( "%d\n" ,x);
}
MyFun 的函数名与 FunP 函数指针都是一样的,即都是函数指针。但是MyFun 函数名是一个函数指针常量,而 FunP 是一个函数数指针变量。
- FunP 函数指针变量可以如“ (*MyFun)(10) ”这样调用,也可以 “ FunP(10) ”的形式来调用
- 赋值时,即可“ FunP = &MyFun ” 形式,也可“ FunP = MyFun ”。
- 在函数的声明处:
void MyFun(int); //不能写成 void (*MyFun)(int)。
void (*FunP)(int); //不能写成 void FunP(int)。
定义某一函数的指针类型
#include<stdio.h>
void MyFun(int x); /*此处的声明也可写成:void MyFun( int )*/
typedef void (*FunType)(int); /*这样只是定义一个函数指针类型*/
typedef int* PINT; /* 为 int* 类型定义了一个 PINT 的别名*/
FunType FunP; /*然后用 FunType 类型来声明全局 FunP 变量*/
int main(int argc, char* argv[])
{
FunType FunC; /*函数指针变量当然也是可以是局部的 ,那就请在这里声明了。 */
MyFun(10);
FunP = &MyFun;
(*FunP)(16);
return 0;
}
void MyFun(int x)
{
printf("%d\n",x);
}
函数指针作为某个函数的参数
#include<stdio.h>
void MyFun1(int x);
void MyFun2(int x);
void MyFun3(int x);
typedef void (*FunType)(int ); /*定义一个函数指针类型*/
void CallMyFun(FunType fp,int x);
int main(int argc, char* argv[])
{
CallMyFun(MyFun1,10); /*通过 CallMyFun 函数分别调用三个不同的函数 */
CallMyFun(MyFun2,20);
CallMyFun(MyFun3,30);
}
void CallMyFun(FunType fp,int x)
{
fp(x);
}
void MyFun1(int x)
{
printf("函数 MyFun1 中输出:%d\n",x);
}
void MyFun2(int x)
{
printf("函数 MyFun2 中输出:%d\n",x);
}
void MyFun3(int x)
{
printf("函数 MyFun3 中输出:%d\n",x);
}