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语言指针的人来观摩。

小生目前才疏学浅,写到的都是基础,一定继续努力。

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值