# C指针简述(一)
小生结合谭老师的C程序设计和自己其他所学,对C语言指针稍有一些掌握,做一些笔记,不当之处,欢迎指正。
1. 数据在内存中的存储和读取
在程序中定义一个变量,在进行程序编译时,系统给这个变量分配内存单元。编译系统根据变量类型,分配相应字节。在Visual C++中,int型分配4个字节,float型分配4个字节,char型分配1个字节。每个字节都有自己对应的编号,可以叫做地址。通过地址可以找到对应的内存单元,地址指向变量单元。
对变量的访问都是通过地址进行的。
访问方式分为直接访问和间接访问,直接访问是通过变量名进行的访问
int a = 10;
printf("a = %d \n",a);
或者
printf("a = %d \n",*(&a));
在编译时,系统已经为 a 分配了按整型存储方式的4个字节,并建立了和地址的对应表。
首先通过变量名找到相应的地址,从该4个字节中按整型数据的存储方式读出整型变量 a 的值
然后按十进制整数格式输出
间接访问是通过地址进行的访问
int a = 10;
int *p;
p = &a;
printf(" %d \n",*p);
定义一个特殊的变量 p ,用它来存放地址。
将 a 的地址存放到变量 p 中,通过变量 p 找到 a 的地址,从而访问 a 的变量
看一下这几句话,反正不吃亏
▶指针就是地址
▶指针变量存放的是地址
▶整型变量存放的是整数
▶字符变量存放的是字符
▶浮点型变量存放的是实数
▶数组“变量”存放的是一串数据
2. 指针变量
2-1. 【指针变量的定义】
指针变量的一般形式为:类型名 *指针变量名;
如 int *p;
也可以对其初始化 int *p = &a;
指针变量前的*
表示该变量为指针型变量。
指针变量只能存放地址,不要将一个整数赋给指针变量
如int *p = 100;
这是不合法的!!!
2-2. 【指针变量的引用】
谭老师C程序设计中的一个指针变量应用的例题
输入a,b两个整数,按先大后小顺序输出a和b。
int *p1,*p2,*p3,a,b;
printf("please enter two integer numbers: ");
scanf("%d %d",&a,&b);
p1 = &a;
p2 = &b;
if(a<b){
p1 = &b;p2 = &a;
}
/*if(a<b){
p3 = p1;p1 = p2; p2 = p3;
}*/
printf("a = %d ,b = %d \n",a,b);
printf("max = %d ,min = %d \n",*p1,*p2);
`a`和`b`的值未发生交换,保持原值。`p1`,`p2`的值发生了改变,原先`p1`的值是`&a`,后来变成`&b`;
`p2`的值是`&b`,后来变成`&a`。这样`*p1`和`*p2`输出的变量就变成了`b`和`a`。
2-3. 【指针变量作为函数参数】
函数的参数不仅可以是整型,浮点型,字符型等,还可以是指针类型。它的作用是将一个变量的地址传送到另一个函数中。
把上面的例题改进一下
void swap(int *data1,int *data2)
{
int temp;
temp = *data1;
*data1 = *data2;
*data2 = temp;
}
int main()
{
int *p1,*p2,a,b;
printf("please enter two integer numbers: ");
scanf("%d %d",&a,&b);
p1 = &a;
p2 = &b;
if(a<b){
swap(p1,p2);
}
printf("max = %d ,min = %d \n",*p1,*p2);
比较简单,这里我就不多说了
但是请记住一点如果**函数参数类型不是指针变量**,那么形参值的改变不能使实参的值随之改变。
指针变量作为函数参数,在函数执行过程中指针变量所指向的变量值发生变化,函数调用结束后,这
些变量值的变化依然可以保留下来。
下面是另一个例题,和上面很相似
输入三个整数,按由大到小顺序输出
#include<stdio.h>
void one(int *d1,int *d2,int *d3)
{
if(*d1<*d2){two(d1,d2);}
if(*d1<*d3){two(d1,d3);}
if(*d2<*d3){two(d2,d3);}
}
void two(int *b1,int *b2)
{
int temp;
temp = *b1;
*b1 = *b2;
*b2 = temp;
}
int main()
{
int *p1,*p2,*p3;
int a,b,c;
printf("please enter three integer numbers:");
scanf("%d %d %d",&a,&b,&c);
p1 = &a;
p2 = &b;
p3 = &c;
one(p1,p2,p3);
printf("%d %d %d\n",*p1,*p2,*p3);
return 0;
}
3. 指针与数组
数组里面每个元素都有自己对应的地址,显然指针变量也可以指向数组元素,数组元素的指针就是数组元素的地址。
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int *p;
p = &a[0]; 或 p = a;//大多数情况下,数组名就是数组首元素的地址
初始化:int *p = &a[0];
或int *p = a;
3-1.【偏移值】
当指针变量p
指向数组元素a[0]
,p+1
表示指向下一个元素a[1]
。
p+1
表示指向同一数组中下一个元素,p-1
表示指向同一数组中上一个元素
a[i]
等同于*(a+i)
等同于*(p+i)
[]
是变址运算符。
整型数组a,输入10个元素,输出全部元素
int i;
int a[10];
int *p;
p = a;
printf("输入十个整数:");
for(i=0;i<10;i++){
scanf("%d",&a[i]);
}
for(i=0;i<10;i++){
printf(" %d ",a[i]);
//printf(" %d ",*(a+i));
//printf(" %d ",*(p+i));
}
也可以用指针变量来指向数组元素,,这样能提高执行效率
int i;
int a[10];
int *p;
p = a;
printf("输入十个整数:");
for(i=0;i<10;i++){
scanf("%d",&a[i]);
}
for(p=a;p<(a+10);p++){
printf(" %d ",*p);
}
3-2.【数组名作函数参数】
数组名作函数参数,实参数组名代表该数组元素的首地址,而形参是用来接收从实参传递过来的数组首元素地址。
形参应该是一个指针变量。
数组中n个元素按相反顺序存放
#include<stdio.h>
void inv(int *x,int len)
{
int *p,*q,*e,temp,m=(len-1)/2;
p=x;q=x+len-1;e=x+m;
for(;p<=e;p++,q--){
temp = *p;
*p = *q;
*q = temp;
}
}
int main()
{
int a[10]={0,1,2,3,4,5,6,7,8,9};
int i;
for(i=0;i<10;i++){
printf("%d ",a[i]);
}
printf("\n");
inv(a,10);
for(i=0;i<10;i++){
printf("%d ",a[i]);
}
return 0;
}
对上述的改进,用指针变量作实参
#include<stdio.h>
#include<stdlib.h>
void inv(int *x,int len)
{
int *p,*q,*e,temp,m=(len-1)/2;
p=x;q=x+len-1;e=x+m;
for(;p<=e;p++,q--){
temp = *p;
*p = *q;
*q = temp;
}
}
int main()
{
int a[10];
int i;
int *p = a;
printf("输入数据:");
for(i=0;i<10;i++,p++){
scanf("%d",p);
}
printf("\n");
p = a;
inv(a,10);
for(p=a;p<a+10;p++){
printf("%d ",*p);
}
return 0;
}
指针方法对输入的10个整数按由大到小排列输出(应用到了冒泡排序法)
#include<stdio.h>
#include<stdlib.h>
void dx(int data[],int len)
{
int i,j,temp;
for(i=0;i<10;i++){
for(j=0;j<len-1-i;j++){
if(data[j]<data[j+1]){
temp = data[j];
data[j] = data[j+1];
data[j+1] = temp;
}
}
}
}
int main()
{
int a[10];
int *p = a;
int i;
printf("输入数据:");
for(i=0;i<10;i++,p++){
scanf("%d",p);
}
printf("\n");
p = a;
dx(a,10);
for(i=0;i<10;i++){
printf("%d ",a[i]);
}
system("pause");
return 0;
}
4. 指针与字符串
4-1.【定义字符数组】
用字符数组存放一个字符串
#include <stdio.h>
#include <stdlib.h>
int main()
{
char a[]="bei jing huan ying nin";//定义字符数组a
printf("%s\n",a); // %s 用来输出a,可以输出整个字符串
printf("%c\n",a[2]); // %c 用来输出一个字符数组元素
system("pause");
return 0;
}
char a[]="bei jing huan ying nin";长度为23,22个字节存放`bei jing huan ying nin`,最后一个字节
存放字符串结束符`\0`。
数组名`a`代表字符数组首元素的地址,`a[2]`就是`*(a+2)`,`a+2`是一个地址,指向字符`i`。
通过字符指针变量输出一个字符串
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *b = "lpl and lck"; //定义字符指针变量 `b` 并初始化(把第一个字符的地址赋给指针变量 `b`)
printf("%s\n",b); // %s 输出字符串
system("pause");
return 0;
}
字符串是放在字符数组里面的,在内存中开辟一个字符数组用来存放该字符串常量,但这个字符数组
是没有名字的,因此不能通过数组名来引用,只能通过指针变量来引用。
对字符串的存取,分为下标法和指针法
例:将字符串a复制为字符串b,然后输出字符串b。
下标法
#include <stdio.h>
#include <stdlib.h>
int main()
{
char a[]="lpl and lck";
char b[20];
int i;
for(i=0;*(a+i) != '\0';i++){
*(b+i) = *(a+i) ;
}
*(b+i)='\0';
printf("a = %s\n",a);
printf("b = %s\n",b);
system("pause");
return 0;
}
注: *(a+i)无条件等于a[i]
指针变量访问字符串
#include <stdio.h>
#include <stdlib.h>
int main()
{
char a[]="lpl and lck",b[20];
char *p1,*p2;
p1 = a;
p2 = b;
for(p1=&a[0];*p1 != '\0';p1++,p2++){ // p1=&a[0] 可以不写
*p2 = *p1;
}
*p2 = '\0';
printf("a = %s\n",a);
printf("b = %s\n",b);
system("pause");
return 0;
}
p1,p2指向字符串a,b的第一个字符
4-2.【字符指针作函数参数】
一个字符串从一个函数传递到另一个函数中,可以用地址传递的方法。用字符数组名作参数,也可用字符指针变量作参数。在被调函数中改变字符串的内容,在主调函数中可以引用改变后的字符串。
例:函数调用实现字符串的控制
用字符数组名作函数参数
#include <stdio.h>
#include <stdlib.h>
void copy(char c[],char d[])
{
int i = 0;
while(c[i] != '\0'){
d[i] = c[i];
i++;
}
d[i] = '\0';
}
int main()
{
char a[]="lpl";
char b[]="lck";
printf("a = %s\n",a);
printf("b = %s\n",b);
copy(a,b);
printf("copy:a = %s\n",a);
printf("copy:b = %s\n",b);
system("pause");
return 0;
}
用字符指针变量作参数
#include <stdio.h>
#include <stdlib.h>
void copy(char *c,char *d)
{
int i = 0;
while(c[i] != '\0'){
d[i] = c[i];
i++;
}
d[i] = '\0';
}
int main()
{
char a[]="lpl";
char b[]="lck";
char *p1,*p2;
p1 = a;
p2 = b;
printf("a = %s\n",a);
printf("b = %s\n",b);
copy(p1,p2);
printf("copy:a = %s\n",a);
printf("copy:b = %s\n",b);
system("pause");
return 0;
}
用字符指针变量作形参和实参
#include <stdio.h>
#include <stdlib.h>
void copy(char *c,char *d)
{
int i = 0;
for(c=&c[0];*c != '\0';c++,d++){
*d = *c;
}
d[i] = '\0';
}
int main()
{
char *a="lpl";
char b[]="lck";
char *p = b;
printf("a = %s\n",a);
printf("b = %s\n",b);
copy(a,p);
printf("copy:a = %s\n",a);
printf("copy:b = %s\n",b);
system("pause");
return 0;
}
copy函数还可以在精练一些
void copy(char *c,char *d)
{
while((*d=*c) != '\0'){
c++;
d++;
}
}还有许多改法,读者可以自行摸索,小生不一一列举了。
后续
如果把上面的代码洞悉,关于指针的其他知识(指针数组,数组指针,函数指针,malloc等等),就显得非常容易。
个人认为此篇文章适合刚接触C语言指针的人来观摩。
小生目前才疏学浅,写到的都是基础,一定继续努力。