指针
1.指针运算
*(p1 - 1) :p1指向的地址减一个存储单元,也就是后移4个字节的地址中存储的数据
*p1 - 1:p1指向的存储单元值减1
2.指针与函数
2.1指向函数的指针
int max(int x,int y){}
int main(void){
int (*p)(int,int);
int a,b,c;
p = max;
scanf("%d %d",&a,&b);
c = (*p)(a,b);
return 0;
}
int (*p)(int,int);//p是一个指向函数的整型指针
c = (*p)(a,b);//p指向函数,相当于调用了函数
2.2返回指针的函数
int *max(int *x,int *y);//max函数调用后返回值的数据类型是整型指针
3.void指针类型
void指针类型,可以用来指向一个抽象类型的数据,在将它的值赋给另一个指针变量时要进行强制类型转换,使之适合于被赋值的变量的类型.例:
char *p1;
void *p2;
p1 = (char *)p2;
p1 = (void *)p2; //可以使用(void *)p1将p1转换成void *类型
不只对变量可以使用void指针类型,也可以将一个函数定义为void *类型
void * fun(char ch1,char ch2);
p1=(char *)fun(ch1,ch2); //类型转换
4.简单链表
#include <stdio.h>
#include <stdlib.h>
struct list{
int data;
struct list *next;
};
typedef struct list node;
typedef node *link;
int main(){
link ptr,head; /*创建指针对象*/
int num,i;
ptr = (link)malloc(sizeof(node)); /*分配空间*/
head = ptr; /*分配空间*/
printf("plesase input 5 numbers==>
"); /*输入数据*/
for(i=0;i<=4;i++){ /*循环创建对象*/
scanf("%d",&num);
ptr->data = num; /*对象赋值*/
ptr->next = (link)malloc(sizeof(node));/*分配空间*/
if(i == 4)
ptr->next = NULL; /*最后一个指针指向空*/
else
ptr = ptr->next; /*指针指向下一个对象*/
}
ptr = head;
while(ptr != NULL){
printf("The value is ==>%d
",ptr->data);/*对象不为空就输入值*/
ptr = ptr->next;
}
return 0;
}
5.指针与数组
&grade[3] = &grade[0] + 3 * 4 //含义是grade[3]的地址等于grade[0]的地址加上12
可以写成以下通式
数组中下标为N元素的地址 = 数组的首地址 + N * sizeof(DataType)
使用数组名访问元素使用指针变量一样
5.1指针与多维数组
int array[1][2];
array + 1 //数组下标1 行首地址
&array[1] //数组下标1 行首地址
array[1] //等价array[1]+0,指array[1][0]元素的地址
array[1] + 2 //array[1][2]的地址
*(array+1)+2 //array[1][2]的地址
*(*(array + 1) + 2) //array[1][2]的值
*(array[1] + 2) //array[1][2]的值
5.2指针与数组参数
6.指针与字符串
字符串的定义自动包含了指针,
例如定义message1[100],为100个字符声明存储空间,并自动创建一个包含指针的常量message1,存储的是message1[0]的地址。与一般的常量一样,指针常量指向是明确的,不能被修改。
字符串,可以不按声明一般数组的方式定义数组的维数和每一维的个数,可以使用新的方法,即用指针创建字符串。例:
char *message2 = "Talk is cheap";
char message1[20] = "Show me the code";
message1与message2不同,message1按照数组定义方式定义,message2用指针创建字符串,message1形式要求有固定的存储该数组的空间,而且,因为message1本身是数组名称,一旦初始化,再执行下面的语句就是错误的:
message1 = "hello !";
message2本身是一个指针变量。通过显式的方式明确了一个指针变量,对于message2执行了初始化后,再执行下面的代码是正确的:
message2 = "hello !";
从分配空间的角度分析,二者也不同。message1指定了一个存储10个字符位置的空间。message2不同,它只能存储一个地址,只能保存指定字符串的第一个字符的地址。
7.指针的指针
使用指针的指针访问字符串数组
int main(){
char *seasons[]={"winter","spring","summer","fall"};
char **p;
int i;
for(i=0;i<4;i++){
p=seasons+i;
printf("%s
",*p);
}
return 0;
}
seasons是指针数组,每个元素都是指针,seasons是字符串"winter"的指针,seasons+i等价与&seasons[i],也就是每个字符串首字符的地址。
8.指针数组和数组指针
指针数组是指数组由指针类型的元素组成。比如 int *p[10],数组p由10个指向整型元素的指针组成;比如p[0],是一个指针变量,使用跟一般指针用法一样,就是这些指针有同一个名字,需要使用下标来区分。
int main(){
int array[2][3] = {1,2,3,4,5,6};
int i,j;
int (*p)[3];
p = array;
for(i = 0;i < 2;i++){
for(j = 0;j < 3;j++)
printf("array[%d][%d] = %d
",i,j,p[i][j]);
}
return 0;
}
/**
**报数游戏
**从第1个报数,报到3的退出,问最后留下来的是哪个
**/
int main(){
int i,k,m,n,num[nmax],*p;
printf("输入总人数:");
scanf("%d",&n);
p = num;
for(i = 0;i < n;i++)
*(p + i) = i + 1;//赋值
i = 0;k = 0;m = 0;//m:退出的人数 k:报的数 i:地址偏移
while(m < n - 1){
if(*(p + i) != 0)
k++;
if(k == 3){
*(p + i) = 0;
k = 0;//报到3恢复0
m++;
}
i++;
if(i == n)
i = 0;//数组结束 重置到数组首地址
}
while(*p == 0)
p++;
printf("%d 号留下了
",*p);
return 0;
}