指针
- 如何知道数组大小
int a[] = { 1,2,3,4,5 };
char s[] = {'a','b','c','d','e'};
int n, m;
n = sizeof(a) / sizeof(int);
m = sizeof(s) / sizeof(char);
- 指针概念(什么是指针?)
简洁说法:指针是地址
详细说明:在C语言中,内存单元的地址称为指针,专门用来存放地址的变量,称为指针变量
- 指针运算
指针运算是以指针变量所存放的地址量作为运算量而进行的运算
指针运算的实质就是地址的计算
指针运算的种类是有限的,它只能进行赋值运算、算术运算和关系运算
- 指针运算
注意:(1)指针p++,--p;(2)数组a[10],a++错误
原因:p为指针地址,是变量可以改变,a是数组地址,是常量,不可以改变
- 指针与数组
char str={“Hello World”};
4.1<指针变量>char* p=str; //可修改,原因如下
------------错误--const char*不能初始化char*----------------------------------------------------------
4.2<数组的指针> char* p=“Hello World”; //不可修改,原因如下
注意:(1)char* p=“Hello World”;在新版已经不可用,必须const char* p=“Hello World”;防止字符串常量被修改.
(2)printf(“%s”,*p);错误,%s输出的是地址,应该是printf(“%s”,p);
两者区别:
1.(同)<指针变量>和<数组的指针/数组名>在访问数组中元素时,一定条件下其使用方法具有相同的形式,因为指针变量和数组名都是地址量
2.(区)<指针变量>和<数组的指针(或叫数组名)>在本质上不同,指针变量是地址变量,而数组的指针是地址常量,而地址常量不能修改,因为在静态储存区,所以数组的指针char* p=“Hello World”;不能修改字符,只能重新指向其他字符串
静态存储区:不能修改,且在程序运行时不会失效
处在静态存储区的变量:(1)全局变量(2)static静态变量(3)字符串常量(char* p=“Hello World”;)
5.一级指针遍历二级数组
int a[4][3] = { {1,2,3},{2,3,4},{3,4,5},{4,5,6} };
int* p=a[0];
printf("%d %d\n", *(p + 1), a[0][1]);
注意:
(1)二级数组地址连续,a[0]与p都是同型地址,即加一地址一样(a[0]+1与p+1地址一样),所以可以赋值运算.
(2)a与p不是同型地址,即(pinrtf("%p"),a+1);(pinrtf("%p"),a+1);不一样,a+1地址加3个地址 单位,p+1加1个地址单位),所以不可赋值.
(3)1个地址单位在32位中是4字节,在64位为8字节.
5.1 printf("%d %d\n", a[0][0], a[1][0]);
printf("%d %d\n", *a[0], (*a+1)[0]);
两者等价,a[0]可以用*a直接替代
- 数组指针(行指针)
简言之:指向数组的指针,使用后等价数组
int a[2][3]; int (*p)[3];p=a;
之后就可以p替代a,例如p[0][0]替代a[0][0]
行指针(数组指针)存储行地址的指针变量,叫做行指针变量。
注意:数组指针int (*p)[3];相当于数组
6.指针数组
简言之: 若干指针变量构成集合
详细: 指由若干个具有相同存储类型和数据类型的指针变量构成的集合
Int * p[2],a[2][3];
p[0]=a[0];p[1]=a[1];
这样p[0]指针指向a[0],p[1]指针指向a[1]
7.多级指针
7.1多级指针基本用法
Int a=10;
Int* p=&a;
Int* * pp=&p;
7.2多级指针与指针数组结合
Int a[]={3,6,9};
Int* p[2]={&a[0],&a[1]};
Int* *q=p;//等价int* *q=&p[0]
这样就组成了多级指针
**q *p[0] a[0]相互等价
**(q+1) *p[1] a[1]相互等价
7.3多级指针与字符串的结合
char *s={“apple”,”pear”};
char **p=s;//p=&s[0];
- void指针
void指针是一种不确定数据类型的指针变量,它可以通过强制类型转换让该变量指向任何数据类型的变量
int* m=10;
double n=3..14;
void *p,*q;
p=(void *)&m;//也可以不强制转换 p=&m;即可
printf(“%d %d\n”,m,*(int *)p);
q=(void *)&n;
printf(“%.2f %.2f\n”,n,*(double*)p);
注意:
- 在输出的时候需要强制转换
原因:int占4字节,double占8字节,void类型不知道要找4地址还是8地址,所以转换
- void指针,在没有强制类型转换之前,不能进行任何指针的算术运算
不强制转换时不能运算处理,即q++,q+1;操作不可
原因:void类型指针不知道指向哪里了,随机
8.1void遍历数组
int a[]={1,2,3,4,5};
void * p;
for(int i;i<n;i++){
printf(“%d”,*((int*)p+1));
}
注意:先强制类型转换,再加偏移量i,加*变指针
- const变量
int m=10;
const int *p=&m;
(*p)++;-->error: const修饰后,变量变为常量,不能修改
int * const q;
q=&m;-->error:const在中间,指针不能修改指向
解决: int* const q=&m;直接一开始就指向m;
<结论>:const修饰谁,谁不能修改
const int *p=&m;//修饰*p,*p不能改
int * const q;//修饰q,q不能改
const int* const rn=&m;//const修饰*rn,修饰rn,所以不能修改*rn,rn
10.main函数参数的讲解
<运行时输入> ./a.out 192.168.1.7 6000
int main(int argc,const char* argv[]){
printf(“argc=%d”,argc);
<输出>argc=3 原因:我输入三个参数(./a.out,ip地址,6000)
for(int i=0;i<argc;i++){
printf(“%s\n”,argv[i]);
<输出>我输出的三个参数(./a.out,ip地址,6000)
}
return 0;
}
- 指针函数
简言之:函数的返回值为地址量的函数
#include <stdio.h>
#include <string.h>
char * mystring( ) {
char str[20];
strcpy(str, “Hello”);
return str;
}
int main(void)
{
printf(“%s\n”, mystring());
return 0;
}
//错误点
(1)mystring()函数的char str[20];在函数结束失效,内容清除,所以接收不到
(2)解决方式:1.str[20]改成全局变量2.static变量的地址3.字符串常量地址(char* str=”hello”)4.堆地址(malloc申请地址)
- 函数指针
简言之:指向函数的指针
函数指针用来存放函数的地址,这个地址是一个函数的入口地址
函数名代表了函数的入口地址
int add(int a, int b) {
return a + b;
}
int main() {
int (*p)(int, int);//函数指针
p = add;
printf("%d", (*p)(6, 10));
return 0;
}
12.1函数指针数组
函数指针数组是一个保存若干个函数名的数组
int add(int a, int b) {
return a + b;
}
int sub(int a, int b) {
return a - b;
}
int main() {
int (*p[2])(int, int);
p[0] = add;
p[1] = sub;
printf("%d", (*p[0])(6, 10));
printf("%d", (*p[1])(6, 10));
return 0;
}