指针
1. 定义一个指针变量p,类型是int* ,指向一个int型的数据
int *p
涉及的指针符号:* &
p = &a;//指针的绑定
*p = 23;//指针的解引用,*p得到了变量(a)
2. 定义指针的同时并且初始化
int *p1 = &a; // == int *p, a; p = &a
3. 指针的运算,就是加减指针所指向的变量类型所占字节大小
同一数组中,两指针相减可得出元素的个数。如果是两个数组的指针相减,将导致未定义的结果
int arr[5] = {1, 3, 5, 7, 9};
int *p = arr;
int *q = arr+5;//指向9的后一位
int ret=q-p;//元素个数
4.野指针
int *p;
危害:1、直接指向内核区 2、指向可用也没有别的数据的区域 3、可用但有别的数据
//NULL专用于指针的初始化(写0)
int *p = NULL;
6.指针与函数值传递
void fun(int *p)//可以不需要返回值
{
*p=1;//直接修改main中变量
}
int main(void)
{
int a=0;
fun(&a);//传入地址
return 0;
}
7.数组指针与函数传递
#include<stdio.h>
int func(int *p,int lenth)//传入数组元素个数,保证函数接口明确,可以正确调用
{
...
}
int main(void)
{
int arr[3]={1,2,3};
func(arr,3);//数组名作为指针传递
}
8.数组内的指针与解引用
#include<stdio.h>
int main(void)
{
//知识点
//1.*与++有相同的优先级
//2.++后置表示,先传递当前值,完成运算之后再++
int arr[]={1,3,5,7,9};
int *p=arr;
*p++; //*p、p++
*(p++); //p的值给*,p++
//以上两者相同
(*p)++; //*p、*p整体++,即数值++
*++p;
*(++p);//两者相同
#include<stdio.h>
int main(void)
{
//3.printf由右向左入值
int arr[]={1,3,5,7,9};
int *p=arr;
printf("(*p)++ = %d *p = %d.\n", (*p)++, *p);
//输出1,1
printf("*p = %d (*p)++ = %d.\n", *p, (*p)++);
//将输出1,2
}
9.指针数组
int arr[5] = {1, 2, 3, 4, 5}, i = 0;
//指针数组,是一个数组,里面的元素是指针
int *p_arr[5];
// p_arr[0] = arr;//指针数组第一个元素存储数组首元素首地址
// p_arr[1] = arr + 1;//指针数组第二个元素存储数组第二个元素地址
//可以写成for循环
for (i=0; i<5; i++)
{
p_arr[i] = arr + i;
}
printf("*p_arr[2] = %d.\n", *p_arr[2]);
9.函数指针
定义一个函数指针, 并且绑定, C语言里对于函数名的绑定有两种方式:
func、&func,通常写成func
void (*p)(void) = &func或func;
调用函数, 指针的解引用
p 、( )或(*p)( )
10.数组指针与普通数组的绑定与解引用
#include <stdio.h>
int main(void)
{
int a[3] = {1,3,5};
int(*p)[3] = a;
//普通数组
printf("sizeof(a)=%d\n", sizeof(a));//12
printf("a=%d\n", a);//a
printf("a+1=%d\n\n",a + 1);//a+4
printf("sizeof(&a)=%d\n", sizeof(&a));//4
printf("&a=%d\n", &a);//a
printf("&a+1=%d\n\n", (&a) + 1);//a+12
//数组指针
printf("sizeof(*p)=%d\n", sizeof(*p));//12
printf("(*p)=%d\n", *p);//9436216
printf("(*p)+1=%d\n\n", (*p) + 1);//9436220
printf("sizeof(p)=%d\n", sizeof(p));//12
printf("p=%d\n", (p));//a
printf("p+1=%d\n\n", (p + 1));//a+12
printf("sizeof(*(*p)=%d\n", sizeof(*(*p)));//4
printf("*(*p)=%d\n", (*(1=%d\n\n", (*(*p))
可以看出,数组指针中的*p相当于普通数组中的数组名a,p相当于普通数组中的&a
const
const 关键字, 修饰的变量是常数,不可更改。只能初始化一次。
const修饰一个普通变量
#include<stdio.h>
int main(void)
{
const int a=0;//const修饰a,只能初始化一次
a=3;//错误,不可以直接通过a修改内容
int *p=NULL;
p=&a;
*p=2;//正确,可以通过指针更改内容
printf("%d",a);
return 0;
}
const修饰一个指针类型变量
const int *p;//const修饰*p,p的内容不可更改
int const *p;//同上
int * const p;//const修饰p,p本身不可修改
const int *const p;//const修饰p本身及其内容,均不可改
malloc
堆内存也是内存的一种,需要程序员自己手动申请malloc,手动释放
编译器不会自动回收,申请的内存伴随整个程序
流程:申请,判断成功,初始化,使用,释放,指针设置为空
注意:malloc申请的空间,默认是有最小分配的
If size is 0, then malloc() returns either NULL, or a unique pointer
value that can later be successfully passed to free().
如果长度为0,则返回不是空指针,而是一个可以被成功返回的唯一指针。
typedef
1.typedef int my_int//将int重命名为my_int
2.typedef char * my_char//将char*重命名为my_char
3.typedef (void (*p)(void)) my_func//将void * void 类型的函数重命名为my_func
4.typedef void (*p_arr[10])(void);//函数指针数组:数组里面的元素都是指针(函数指针)
二维数组
二维数组的变量名是首元素首地址{arr[0], arr[1]}
int arr[2][3] = {1, 2, 3, 4, 5, 6};
arr代表数组首元素首地址(&arr[0])
&arr[0]代表第一维数组的首元素首地址
&arr[0][0]代表数组的第二维数组是首元素首地址
int arr[2][3] = {1, 2, 3, 4, 5, 6};
int (*p)[3];//数组指针, 指针指向了一个int[3]类型的数据结构
p = arr;
//指针方式遍历二维数组
int i = 0, j = 0;
for (i=0; i<2; i++)
{
for (j=0; j<3; j++)
printf("*(*(p+%d)+%d) = %d.\n", i, j, *(*(p+i)+j));
}
实现:
利用传值调用实现swap功能
利用malloc申请动态数组,完成排序