函数指针
如果在程序定义了一个函数,在编译时,编译系统为函数代码分配一段存储空间,这段存储空间的起始地址,称为这个函数的指针
函数名就是函数开始的地址
函数二级指针可以修改函数指针的指向
函数指针,不仅仅是地址,必须明确函数指针类型和输出参数类型和数量
函数名可以作为参数传递给函数指针
函数的返回值可以是指针
左值,能放在赋值号左边的值
int *const px; //指针常量
指针包括 类型和地址,将地址转换为指针,需要进行类型的转换
如:
int* p;
int x;
scanf("%x",&x);
p = (int*) x; //将地址转换为指针
void指针和空指针
void* 类型的指针,只包含地址不包含类型,是不指向任何类型的指针,任何类型都可以赋值给空类型指针,纯地址的赋值,但指向不明确,大小不确定,无法取出内容,如果需要取读地址的内容
应先对地址进行类型的转换,一般用于参数还有返回值,不明确指针类型的情况传递地址,如 malloc() 函数的返回值
int* p =NULL;//不指向任何地址,即没有初始化,空指针,*p等价于int类型,p等价于int*类型
void *p = malloc(20); //分配20个字节的内存,返回值赋值给void*类型指针变量p,可以转换成任何类型的指针,malloc函数在stdlib.h头文件中
int *px = (int*)p; //强制转换指针类型,使分配的内存可以按照int类型解析
ferr(p); //根据地址释放指针,此时p为迷途指针
静态内存分配由编译器完成,如为一个不大的数组分配内存
return 也有副本机制,存储在寄存器中,无法取地址
char *p = "你好,明天"; //指针存储常量字符串首地址,常量字符串不能修改
一级指针75% 二级指针20%,三级 四级指针.....N级指针 用于权限管理???
没有初始化的指针叫也指针
更高级指针可以改变低级指针的指向
指针声明一定要初始化
#作用:加上双引号
如果在程序定义了一个函数,在编译时,编译系统为函数代码分配一段存储空间,这段存储空间的起始地址,称为这个函数的指针
函数名就是函数开始的地址
函数二级指针可以修改函数指针的指向
函数指针,不仅仅是地址,必须明确函数指针类型和输出参数类型和数量
函数名可以作为参数传递给函数指针
#include <stdio.h>
#include <stdlib.h>
int add(int a, int b)
{
return a + b;
}
void print()
{
printf("你好,明天\n");
}
int main()
{
printf("%p %p\n", add, print);
void(*p)() = print; //声明函数指针,并初始化函数指针
int(*pa)(int a, int b) = add; //声明函数指针,并初始化函数指针
//初始化指针只能传递地址
print(); //直接调用
p(); //调用函数指针,相当于调用函数,间接调用
printf("%d\n",pa(12,36));
system("pause");
}
函数的返回值可以是指针
#include <stdio.h>
#include <stdlib.h>
#include<time.h>
//函数,返回一个地址,对于数组而言,函数参数调用没有副本机制
//函数返回值是一个指针类型的函数
int* mindata(int a[], int n) //查找最小数
{
int *p = NULL; //声明指针变量,指向空指针,最后保存最小值的地址
int min = a[0];
p = &a[0];
for (int i = 1; i < n; i++) //选择法
{
if (min > a[i])
{
min = a[i];
p = &a[i];
}
}
printf("最小的值为%d\n",*p);
return p; //返回最小值的地址
}
int main()
{
int a[10];
time_t ts;
srand((unsigned int)time(&ts)); //按照时间设置随机数种子
for (int i = 0; i < 10; i++)
{
a[i] = rand() % 100;
printf("%d\n",a[i]);
}
int *p = mindata(a,10); //获取最小数的地址
//此时 直接修改*p 可以起到修改最小值 如,*p = 35;
printf("%d\n",p -a); //可以知道下标符号
system("pause");
}
左值,能放在赋值号左边的值
int *const px; //指针常量
写一个和strcpy函数功能相同的函数
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//写一个和strcpy函数功能相同的函数
char* mystrcpy(char* dest, char* source) //两个参数目的 ,来源
{
char * last = NULL; //最后结果
if (dest == NULL || source == NULL)
{
return last; //如果传入的两个字符串有一个是指向空指针的,结束函数
}
last = dest;//存入首地址
while ((*dest++ = *source++) != '\0');
//没有遇到字符 '/0',一直拷贝数据
return last;
}
int main()
{
char str[40] = {0};
//char * p = mystrcpy(str, "你好明天\n"); //声明一个指针接受字符串str的首地址
//printf("%p %p\n",str,p); 地址相同
//printf("%s", p);
//printf("地址为%p\n", strcpy(str, "你好明天\n"));//strcpy函数返回字符串str的地址
printf("%s", strcpy(str, "山阴路的夏天\n")); //两条语句的作用相同,函数没有问题
printf("%s", mystrcpy(str, "你好明天\n")); //两条语句的作用相同,函数没有问题
system("pause");
}
指针包括 类型和地址,将地址转换为指针,需要进行类型的转换
如:
int* p;
int x;
scanf("%x",&x);
p = (int*) x; //将地址转换为指针
void指针和空指针
void* 类型的指针,只包含地址不包含类型,是不指向任何类型的指针,任何类型都可以赋值给空类型指针,纯地址的赋值,但指向不明确,大小不确定,无法取出内容,如果需要取读地址的内容
应先对地址进行类型的转换,一般用于参数还有返回值,不明确指针类型的情况传递地址,如 malloc() 函数的返回值
int* p =NULL;//不指向任何地址,即没有初始化,空指针,*p等价于int类型,p等价于int*类型
void *p = malloc(20); //分配20个字节的内存,返回值赋值给void*类型指针变量p,可以转换成任何类型的指针,malloc函数在stdlib.h头文件中
int *px = (int*)p; //强制转换指针类型,使分配的内存可以按照int类型解析
ferr(p); //根据地址释放指针,此时p为迷途指针
p = NULL;
动态内存分配
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
//void* calloc(size_t num.size_t size)
//分配内存函数,第一个参数为个数,第二个参数为内存大小,内存自动初始化为0
//void* realloc(void *ptr,size_t size)为以分配的内存重新分配空间并复制内容。
//参数一,已分配的内存地址,参数二重分配的字节数 如果能拓展就拓展,不能就重新分配
int main()
{
int x;
scanf("%d",&x);
int *p = (int *)malloc( sizeof(int) * x ); //分配 x乘于int类型字节数的内存
//分配失败则返回一个空指针NULL,返回值为空类型指针 malloc(1024) == NULL 判断是否分配成功
//指针变量p指向分配的内存之后,不应更改指针的指向
//实现动态数组,按照数组的方式访问,
for (int *px = p,i = 0; px < p+x; i++,px++) //指针法
{
*px = i;
printf("%d\n",*px);
}
free(p); //根据地址释放内存,一定要记得释放内存,除非空指针能反复释放
p = NULL;
//内存释放之后,指针应该赋值为空,可以规避再次引用和反复释放的问题
//for (int i = 0; i < x; i++) //下标法
//{
// p[i] = i;
// printf("%d\n",p[i]);
//}
system("pause");
}
静态内存分配由编译器完成,如为一个不大的数组分配内存
动态内存分配
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
void detection(float* str)
{
for (int i = 0; i < 5; i++)
{
if (str[i] < 60)
printf("不及格成绩为%.2f 第%d个\n", str[i], i + 1);
}
}
int mainaa()
{
float* p = (float*)malloc(5 * sizeof(int));
printf("输入五个成绩并以空格隔开\n");
scanf("%f %f %f %f %f", p, p + 1, p + 2, p + 3, p + 4);
detection(p);
free(p); //释放内存
system("pause");
}
return 也有副本机制,存储在寄存器中,无法取地址
一级指针作为函数返回值返回地址,一定不能返回指向栈的地址
#include<stdio.h>
#include <stdlib.h>
//void swap(int* pa, int* pb) //无法交换pa pb的值
//{
// int *p = pa;
// pa = pb;
// pb = pa;
//
//}
void swap(int* pa, int* pb) //可以交换pa pb的值
{
int *p = pa;
*pa = *pb;
*pb = *p;
}
int main()
{
int a, b;
int *pa = &a, *pb = &b;
scanf_s("%d %d", pa, pb);
printf("%d %d\n", a, b);
swap(pa,pb);
printf("%d %d\n", a, b);
system("pause");
}
char *p = "你好,明天"; //指针存储常量字符串首地址,常量字符串不能修改
一级指针75% 二级指针20%,三级 四级指针.....N级指针 用于权限管理???
没有初始化的指针叫也指针
更高级指针可以改变低级指针的指向
指针声明一定要初始化
#作用:加上双引号