C的精髓指针,本文基于C程序设计(谭浩强版)所写。
指针
直接访问
间接访问
指针:一个变量的地址称为该变量的“指针”。
指针变量:存放另一变量地址的变量。
指针变量的值是地址(指针)。
指针变量
类型名 *指针变量名;
类型名 是定义指针变量时必须指定的“基类型”。指针变量时基本数据类型派生出来的类型,它不能离开基本类型而独立存在。
一个变量的指针包含两个方面,一是以存储单元编号表示的地址(如编号为2000的字节),一是它指向的存储单元的数据类型(如int,char,float)。
int *a;//a是指向整型数据的指针变量
float *b;//b是指向单精度型数据的指针变量
char *c;//c是指向字符型数据的指针变量
指针类型:int */char */float *
指针变量中只能存放地址(指针),不要将证一个整数赋给一个指针变量。
比如* pointer = 100
是错误的。
引用指针变量
- 给指针变量赋值。
p=&a
- 引用指针变量指向的变量。
* p
- 引用指针变量的值。
p
&/*
- & 取地址运算符。
- * 指针运算符。
示例:
#include <iostream>
#include <stdlib.h>
using namespace std;
<!-- 错误,交换的是形参a,b的值,即二者地址进行了交换 -->
//void swap(int *a,int *b)
//{
// int *temp;
// temp = a;
// a = b;
// b = temp;
//}
<!-- 正确,交换的是形参a,b所指向地址的值,进而改变主函数中的a,b -->
void swap(int *a,int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int a,b;
a = 5;
b = 3;
swap(&a,&b);
cout<<a<<" "<<b;
system("pause");
return 0;
}
通过指针引用数组
数组元素的指针就是数组元素的地址。
int a[10];
int *p;
p = &a[0];//p的值是a[0]的地址
p = a;//p的值是a首元素(即a[0])的地址。
//**数组名不代表整个数组,只代表数组首元素的地址。**
当指针指向数组元素时,p+1指向同一数组中的下一个元素p-1指向同一数组中的上一个元素。
当两个指针p1,p2指向统一数组时,p2-p1的值是地址差除以元素的长度。即二者相差的元素的个数。两地址相加是没有意义的。
通过指针引用数组元素
- 下标法,a[i]
- 指针法,(a+i);(p+i)
示例(混搭大法好啊_):
#include <iostream>
#include <stdlib.h>
using namespace std;
int main()
{
int a[10],i;
int *p = a;
cout<<"请输入是个整数:"<<endl;
for (i=0;i<10;i++)
{
scanf("%d",p++);//不能用cin>>(p++);语法错误
}
p = a;
for (i=0;i<10;i++)
{
printf("%d",*(p++));//cout<<*(p++)<<endl;二者均可
}
system("pause");
return 0;
}
通过指针引用多维数组
以二维数组为例
int a[3][4];
表示形式 | 含义 | 地址 |
---|---|---|
a | 二维数组名,指向一位数组a[0],即0行首地址 | 2000 |
a[0],[a+0],a | 0行0列元素地址 | 2000 |
a+1,&a[1] | 1行首地址 | 2016 |
a[1],*(a+1) | 1行0列元素a[1][0]的地址 | 2016 |
a[1]+2,*(a+1)+2,&a[1][2] | 1行2列元素a[1][2]的地址 | 2024 |
(a[1]+2),(*(a+1)+2),a[1][2] | 1行2列元素a[1][2]的值 | 元素值13 |
通过指针引用字符串
char string[] = "hello";
printf("%s\n",string);
printf("%c\n",string[4]);
printf("%c\n",*(string+4));
字符数组与字符指针变量区别
- 字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第一个字符的地址)。
- 可以对字符指针变量赋值,但不能对数组名赋值。正确:
char *a;a="zdy"
;错误:char str[10];str = "zdy"
- 初始化方式。
char *a = "zdy";char str[10] = "zdy"
- 存储单元内容。编译时为字符数组分配若干存储单元;对字符指针变量,只分配一个存储单元(VC 4个字节)。
char *a;scanf("%s",a);//错误,将a指向键盘输入的字符串。
char *a,str[10];a = str;scanf("%s",a);//正确。 - 指针变量的值可以改变,但是数组名代表一个固定的值,不能改变。
指针数组
类型名 *数组名[数组长度];
int *p[4];
动态内存分配
malloc
void *malloc(unsigned int size);
函数返回分配区域的第一个字节的地址。指针的基类型为void,即不指向任何类型的数据,只提供一个地址。执行失败返回NULL。
示例:
malloc(100);
calloc(动态数组)
void *calloc(unsigned n,unsigned size);
在内存动态从存储区中分配n个长度为size的连续空间。可以为一位数组开辟动态存储空间。即动态数组。函数返回所分配域的起始地址的指针,失败返回NULL。
示例:
p = calloc(50,4);开辟50*4字节,起始地址赋给指针变量p。50个长度为4的数组。
free
void free(void *p);
释放p所指向的动态空间。p是最近一次调用calloc或malloc函数时得到的函数返回值。free函数无返回值。
示例:
free(p);
realloc
void *realloc(void *p,unsigned int size);
将p所指向的已分配的动态空间大小改为size。
示例:
realloc(p,50);//将p所指向的已分配的动态空间改为50字节。
示例:
#include <iostream>
#include <stdlib.h>
using namespace std;
int main()
{
void check(int *);
int *p;
p = (int *)malloc(5*sizeof(int));// p = malloc(5*sizeof(int));亦可
printf("请输入五个学生的成绩:");
for (int i = 0;i<5;i++)
{
scanf("%d",p+i);
}
check(p);
system("pause");
return 0;
}
void check(int *p)
{
printf("低于60分的有:");
for (int i = 0;i<5;i++)
{
if (p[i]<60)
{
printf("%d ",p[i]);
}
}
}