“这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战”
1指针
📍下述的概念在使用的时候统称为指针。
- 地址:内存单元的编号
- 指针:存放地址的内存单元就叫做指针
- 指针变量:存储地址的变量,就叫做指针变量
📢指针指向的那一块内存就是四个字节
1.1指针的定义格式
- char *p; //字符指针
- short *q; //短整型指针
- int *t; //整型指针
- float *w; //浮点类型的指针
- void *l; //实例如下
- //char a = 100; l = (void *)&a;
- //int b = 200; l = (void *)&b;
- char *:指针的类型
- p :指针变量,赋的值是地址
- [* :在定义指针的时候,这个*只是表示p是一个指针变量,
- 除此之外没有其他含义]
- &p :取p指针变量的地址
- 指针内存: 在32位操作系统上指针都是占用的4个字节
- 指针的类型:表示指向内存单元中数据的类型。
1.2指针的用法
int a = 10;
int b;
int *p; //这里的*只是标识p是一个指针变量
p = &a;
*p = 100; //==>向p指向的内存单元中写入100的值
b = *p; //==>读取p指向的内存单元中的数据,并赋值给b;
1.3指针的经典用法
❌
void swap(int a,int b) //不能交换
{
a ^=b;
b ^=a;
a ^=b;
}
✔
void swap1(int *a,int *b) //可以交换
{
*a ^=*b;
*b ^=*a;
*a ^=*b;
}
> > 📝练习1:实现函数mystrcpy
#include <stdio.h>
void mystrcpy(char *p,char *q)
{
while(*p){
*q++ = *p++;
}
*q = '\0';
}
int main(int argc, char const *argv[])
{
char a[50] = {0};
char b[50] = {0};
printf("input:");
scanf("%[^\n]",a);
mystrcpy(a,b);
printf("b=%s\n",b);
return 0;
}
> > 📝练习2:请输入一个字符串,将字符串中的空格删除
#include <stdio.h>
void mystrcpy(char *p,char *q)
{
while(*p){
*q++ = *p++;
}
*q = '\0';
}
void DeleteSpace(char *a)
{
char *tmp;
while(*a){
if(*a != ' '){
a++;
continue;
}else{
tmp = a;
while(*a == ' ' && *a !='\0')a++;
mystrcpy(a,tmp);
a = tmp;
if(*a=='\0')continue;
}
a++;
}
}
void DeleteSpace1(char *a) //改进
{
char *tmp;
while(*a){
if(*a == ' '){
tmp = a;
while(*a == ' ')a++;
mystrcpy(a,tmp);
a = tmp;
if(*a=='\0')continue;
}
a++;
}
}
int main(int argc, const char *argv[])
{
char a[50] = {0};
printf("input string > ");
scanf("%[^\n]",a);
DeleteSpace(a);
printf("a = %s\n",a);
return 0;
}
> > 📝练习3:请输出一个字符串"this is a book",使用指针
#include <stdio.h>
#include <string.h>
void swap(char **a,char **b)
{
while(*a < *b){
**a = **a^**b;
**b = **a^**b;
**a = **a^**b;
(*a)++;
(*b)--;
}
return;
}
void change_word(char *p)
{
char *a,*b,*c;
int len = strlen(p);
a = p;
b = p + len -1;
swap(&a,&b);
a =p;
b =p;
while (*b){ //这里为何为*b
while((*b != ' ') && *b){
b++;
}
c = b--;
swap(&a,&b);
if (*c == '\0')break;
a = b = c+1;
}
printf("%s\n",p);
}
int main(int argc, char const *argv[])
{
char s[100];
printf("请输入字符串:");
scanf("%[^\n]",s);
change_word(s);
return 0;
}
1.4什么是野指针?
- 在定义完指针之后,没有对指针赋值,这个指针是随机值,此时这个指针就是野指针。
//全局变量野指针为0
如何规避野指针?char *p = NULL;
2指针数组
-
指针数组:它本身是一个数组,数组中的成员是指针
-
定义格式如下:
char *p[3];int *t[3];
[3]:有三个成员
p :是有三个char *成员的数组
p[0] = "hello"; //将字符串的首地址赋给 p[0]指针
p[1] = "list";,
p[2] = "tttt";
char *:数组中成员的类型
在定义主函数时,使用快捷键 main + tab键,括号内的含义
命令行:
./a.out hello world ttt
-----------------------------------------
int main(int argc, const char *argv[])
| |
命令行参数的个数 指针数组,表示是哪个成员
argc = 4;
argv[0] = "./a.out"; //对应字符串的首地址
argv[1] = "hello"
argv[2] = "world"
argv[3] = "ttt"
3二级指针
-
二级指针:指向指针的指针就是二级指针
-
定义格式:
char **p;int **q;
**:只是一个标识符号(在定义变量的时候加的**)
p :是一个二级指针
char**:它是指针的类型
- 如何使用二级指针?
int a=10;
int *p = &a;
int **q = &p;
📝练习:地址加加后的含义?
p++ : p向后移动了四个字节0x11223348 *p++ : 取出10的值,然后执行p++ ,p=0x11223348 (*p)++: 将a内存中的值修改为11 q++ : q向后移动四字节0xaabbcce2,p是没有改变的 *q++ : 取出p的地址,然后q向后移动四字节 (*q)++: p向后移动了四个字节0x11223348 **q++ : 取出a中10的值,然后q向后移动4字节 (**q)++:将a内存中的值修改为11
void my_malloc(char **s)
{
*s=(char*)malloc(100);
}
void main()
{
char *p=NULL;
my_malloc(&p);
//do something
if(p)
free(p);
}
4数组指针
-
📢数组指针:它是一个指针,它是一个行指针
-
定义格式:
(char [3]) *p;
(char [3]) a[4];
char (*p)[3]; //有括号的后读括号 ,类型是 char (*)[3]
int (*t)[3];
📑上述的p和t都占4字节,因为他们都是指针
p++ 移动 sizeof(char) * 3
t++ 移动 sizeof(int) * 3
📍实例:
char a[4][3] = {1,2,3,4,5,6,7,8,9,10,11,12};
char (*p)[3];
p = a;
📌注:以后涉及到数组指针的时候,就把它转化成二维数组
**a[i][j]<===>*(a[i]+j)<==>*(*(a+i)+j)** **p[i][j]<===>*(p[i]+j)<==>*(*(p+i)+j)**
📝练习: short a[5][4],(*p)[4]=a;数组a的首地址为100
*(p+2)+3 = &a[2][3]等于?; ☞122
5指针函数
- 指针函数:返回值是指针的函数就是指针函数
char *func(void);
char * strcat(char *dest, const char *src)
//strcat返回拼接后的字符串的首地址
6函数指针
-
函数指针:它是一个指针,这个指针指向函数
-
定义格式:
char (*func)(int a,int b); -
如何使用?
int add(int a,int b)
{
return (a+b);
}
int main(int argc, const char *argv[])
{
int (*func)(int ,int ) = add;
printf("sum = %d\n",func(100,200));
return 0;
}
🔎func是一个指向有两个int参数和一个int类型返回值的函数指针。
func = add;add是函数的名字,本身就是函数的首地址可以直接给func赋值
📝练习:函数指针作为函数的参数?(回调函数)
int add(int a,int b)
{
return (a+b);
}
int sub(int a,int b)
{
return (a-b);
}
void show(int a,int b,int (*func)(int ,int ))
{
printf("sum = %d\n",func(a,b));
}
int main(int argc, const char *argv[])
{
show(100,200,add);//📢add就是函数add的地址
show(100,200,sub);
return 0;
}
7函数指针数组
-
函数指针数组:它是一个数组,数组中存放的是函数指针
-
定义格式:
int (*func[2])(int ,int);
func[0] :存放的int (*)(int,int)的函数指针
func[1] :存放的int (*)(int,int)的函数指针
int (*func[2])(int ,int) = {add,sub};
// func[0] = add;
// func[1] = sub;
printf("sum = %d\n",func[0](100,200));
printf("sub = %d\n",func[1](100,200));
8结构体指针数组,结构体数组指针
8.1结构体指针数组
typedef struct{
char name[20] ;
int age;
char sex;
int score;
struct aa t;
}stu_t;
stu_t *p[3]; //结构体指针数组
p[0] = malloc(sizeof(stu_t));
p[1] = malloc(sizeof(stu_t));
p[2] = malloc(sizeof(stu_t));
8.2结构体数组指针
stu_t (*p)[3]; //它是一个指针,指向一行。
stu_t arr[4][3];
p = arr;