1. 指针和数组
- 数组名称保存的就是数组占用内存最小的那个地址
- 所以指针也可以指向数组
- 结论 如果用指针保存数组的地址后那么 p = arr = &arr
#include <stdio.h>
int main(){
int arr[3] = {1,2,3};
int *p = &arr; // 定义指针变量指向数组arr
printf("arr = %p\n",arr); // arr = 0028FEB0
printf("&arr = %p\n",&arr); // &arr = 0028FEB0
printf("p = %p\n",p); // p = 0028FEB0
return 0;
}
指针可以进行加减法
- 应用场景 : 一般用在指针数组中
- 指针变量+1是加多少,加的就是指针变量类型占用的字节数
- 注意点
-1操作一般企业开发不会用到
- 只有指针才可以做+1-1操作,数组名不可以
#include <stdio.h>
int main(){
int arr[3] = {1,2,3};
int *p = arr;
printf("*p = %i\n",*p); // * p = 1
printf("*(p+1) = %i\n",*(p+1)); //*(p+1) = 2
printf("*(p+2) = %i\n",*(p+2)); // *(p+2) = 3
printf("*p = %i\n",*p++); // 1 ---> p[0]--->1
printf("*p = %i\n",*p++); // 2 ---> p[1]--->2
printf("*p = %i\n",*p); // 3 --->[2]---3
printf("*p = %i\n",*(--p)); // 2
return 0;
}
2. 指针和字符串
- 字符串本质就是数组,所以指针也可以指向字符串
- 正式因为如此 ,所以
定义字符串又多了一种方式
#include <stdio.h>
int main(){
//字符串
char str[] = {'a','b','c','\0'};
char str1[] = "abc";
char *str2 = "eng"; // 指针定义字符串
printf("str = %s\n",str); //str = abc
printf("str1 = %s\n",str1); // str1 = abc
printf("str2 = %s\n",str2); // str2 = eng
return 0;
}
利用数组和指针定义字符串的区别:
- 储存的位置不同
- 如果是通过数组定义的字符串,那么储存在内存的栈中
- 如果是通过指针定义的字符串,那么储存在内存的常量区中
- 由于在内存中储存的位置不一样,所以特性也不一样
- 数组定义的字符串,我们可以手动修改其内容
- 指针定义的字符串,我们不能手动修改
- 数组定义的字符串,每次定义都会重新开辟储存空间
- 指针定义的字符串,重复定义不会重新开辟储存空间
代码如下
#include <stdio.h>
int main(){
char str1[] = "abc";
char str2[] = "abc";
printf("str1 = %p\n",str1); // str1 = 0028FEBC
printf("str2 = %p\n",str2); // str2 = 0028FEB8
char *str3 = "abc";
char *str4 = "abc";
printf("str3 = %p\n",str3); // str3 = 0040407A
printf("str4 = %p\n",str4); // str4 = 0040407A
return 0;
}
- 接受字符串的时候,只能通过字符数组,不能通过字符指针
- 如果函数中返回的字符串是通过数组创建,那么外界无法获取
- 如果函数中返回的字符串是通过指针创建的,那么外界可以获取
字符串数组
- 字符串数组就是一个数组,所以字符串数组就是一个二维数组
- 第一钟格式
#include <stdio.h>
int main(){
char str1 = "abc";
char str2 = "def";
char str3 = "gkk";
char str[][] = { "abc" , "def" , "gkk" };
return 0;
}
- 第二种
char *str1 = "lnj";
char *str2 = "abc";
char *str3 = "def";
char *str[] = {
"lnj",
"abc",
"def"
};
3. 指针变量和函数
- 指向函数的指针
- 计算机也会给函数分配储存空间,既然函数会分配内存空间,所以函数也有自己的地址,所以指针变量也可以保存函数的地址
- 函数和数组很像,函数名中保存的就是函数的地址
1. 如何定义保存函数的指针变量
- 将函数复制过来
- 在函数返回值和函数名称中间加一个*
- 修改函数名称为指针变量的名称
- 注意点 要将" * " 和变量名称用括号括起来
#include <stdio.h>
void test();
int main(){
//1.复制
void test();
//2.中间加*
void *test();
//3. 讲*和变量名称用括号括起来
void (*test)();
//4.修改函数名----->指针变量名
void (*funcP)();
//5.讲test函数的地址给指针变量 funcP
funcP = &test;
void (*funcP)() = &test; //直接声明 + 赋值
return 0;
}
void test(){
printf("hello world");
}
如果通过指针定义后就有三中调用函数的方式
- 第一种 函数名调用
test( );
- 第二种调用
(*funcP)( );
*funcP---指向的就是test的地址
转化为
test( );
- 第三钟调用
funcP( );
指针和结构体
结构体指针
因为结构体变量也会分配内存空间,所以结构体变量也有内存地址,所以可以使用指针保存结构体变量的地址规律
定义结构体变量的指针的方法和定义普通变量的方法一样
如果指针指向了结构体变量,那么访问结构体变量的方法就有三中
1.结构体变量.属性名称
2.(*结构体指针变量名称).属性名称
3.结构体指针变量名称->属性名称
#include <stdio.h>
int main(){
//定义结构体
struct Person {
char *name;
int age;
int money;
};
struct Person per = {"小明",22,100};
struct Person *p = &per;
printf("per.name = %s\n",per.name); // 1. per.name = 小明
printf("(*p).name = %s\n",(*p).name); // 2. (*p).name = 小明
printf("p->name = %s\n",p->name); //3. p->name =小明
return 0;
}
指针和作为函数参数使用
#include <stdio.h>
int test(int num1,int num2,int (*funP)(int,int));
int sum(int num1,int num2);
int min(int num1,int num2);
int main()
{
int res = test(10,20,min); //调用的min函数
printf("res = %i\n",res);
int res2 = test(10,20,sum); //调用的sum函数
printf("res2 = %i\n",res2);
return 0;
}
//注意点: 指向函数的指针,作为函数的形参时, 指针变量的名称, 就是形参的名称
/* 函数在调用的时候test(10,20,sum) 传入的是谁就会指向那个函数
*
*/
int test(int num1,int num2,int (*funP)(int,int)){
return funP(num1,num2);
}
int sum(int num1,int num2){
return num1 + num2;
}
int min(int num1,int num2){
return num1 - num2;
}