CPU(中央处理器)在处理数据的时候,中央的数据在内存中读取,处理后的数据也会放回内存中。
内存会被划分为一个个单元格,每个内存单元的大小取一个字节。每个字节可以放8个比特位,每个内存单元也有一个编号,有了这个编号,CPU可以迅速找到一个内存空间。C语言中把这个编号也叫地址
C语言中给地址起了一个名字叫指针
在C语言中创建变量就是向内存申请空间我们已经知道啦,比如,创建整型变量就是向内存申请4个字节,每一个字节都有地址,
我们通过取地址操作符拿到是一个地址的数值,这个数值有时候需要存储下来,方便后期使用,所以我们这个放在 指针变量 中。
#include
int main()
{
int a = 0;
int* pa = &a;
return 0;
}
这里出现的Int *,*就是代表这个是指针变量。
我们拿到了指针就可以找到指针指向的对象,需要用到一个操作符叫解引用操作符----*
#include
int main()
{
int a = 0;
int* pa = &a;
*pa = 0;
printf("%d", a);
return 0;
}
这里就改变了a的值。
32位平台下地址就是32个bit,指针变量的大小的4个字节
6位平4台下地址就是64个bit,指针变量的大小的8个字节
并且指针变量的大小与类型是无关的,管他什么整型,浮点型,在相同的平台下都是一样的。
指针的类型决定了对指针解引用的时候有多大的权限,比如char类型只能1个字节,而int类型可以4个字节。
可以理解为无具体类型的指针,但是不可以进行指针的+-运算和解引用运算。
变量是可以被修改的,如果我们需要不可以被修改,那我们需要用到const,
对于 int*pa=&a;
const 放在*左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变,但是指针变量本身的内容可以改、
const放在*右边,修饰是指针变量本身
const char *ptr="hello ", 本质就是把hello的首元素存到ptr中
1.指针+-整数
2.指针-指针
3.指针的关系运算
1.指针+-整数:数组在内存中是连续存放, 所以我们只要知道第一个元素的地址,就可以找到所有元素。
2.指针-指针:
#include
int strlen(char* s)
{
char* p = s;
while (*p != '\0')
{
p++;
}
return p - s;
}
int main()
{
printf("%d\n", strlen("abc"));
return 0;
}
野指针就是指针指向的位置是不可知的。
原因:没有初始化,指针越界访问,指针指向的空间释放(就是可能创建的指针变量被销毁了)
1.数组名就是数组首元素的地址,如下图
注意:
sizeof(数组名):计算的是整个数组的大小,单位是字节
&数组名:表示的是取出的是整个数组的地址
#define _CRT_SECURE_NO_WARNINGS
#include
int main()
{
int arr[10];
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = arr;//首元素
int i = 0;
for (i = 0; i < sz; i++)
{
scanf("%d", p+i);
}
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
}
return 0;
}
本质来说,一维数组传参的本质传的是数组的首元素的地址
并且一维数组传参形参部分可以写成数组,也可以写成指针
#include
void test(int arr[])
{
printf("%d\n", sizeof(arr));
}
void test(int* arr)
{
printf("%d\n", sizeof(arr));
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
test(arr);
return 0;
}
二级指针就是存放一级指针的地址
因为你的一级指针存放地址的时候,也需要向内存申请一块空间,它自己本身是需要地址
#include
int main()
{
int a = 0;
int* p = &a;
int** pa = &p;
return 0;
}
整型数组:存放整型的数组
字符数组:存放字符的数组
指针数组:存放指针的数组,也就是说,这个数组里面的每一个元素都是指针
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2 [] = {2,3,4,5,6};
int arr3[] = { 3,4,5,6,7 };
//数组名是元素首元素的地址
int* p[3] = { arr1,arr2,arr3 };
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 5; j++)
{
printf("%d ", p[i][j]);
}
printf("\n");
}
return 0;
}
整型指针变量: int*pint,存放的是整型变量的地址,指向的是整型数据的指针
浮点指针变量:float*pint,存放的是浮点型变量的地址,指向的是浮点型数据的指针
数组指针变量:int(*p)[ ] 存放的是数组的地址,能够指向数组的指针变量
#include
int main()
{
int arr[10] = { 0 };
int(*p)[10] = &arr;
return 0;
}
&arr与*p的类型是完全一致的
二维数组的首元素就是第一行,是一个一维数组
在本质上传的也是地址,传递的就是这个一维数组的地址
函数是有地址的,函数名就是函数的地址,也可以用 &函数名 来表示
int (*p) (int x, int y)........p指向函数的参数类型和个数的交代
. .
. .
. .
. 函数指针变量名字
.
p指向函数返回的类型
#include
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*p)(int, int) = Add;
printf("%d\n", (*p)(2, 3));
printf("%d\n", p(2, 3));
return 0;
}
可以将复杂的类型简单化
比如,你觉得unsigned int 写起来不方便
可以改成 typeof unsigned int uint;
之后你使用就可以直接使用 unit
指针类型也可以改名字
typeof int * ptr-t;
回调函数就是通过函数指针调用的函数
如果你把函数的指针作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数,被调用的函数就是回调函数
回调前
#include
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return a / b;
}
int main()
{
int x, y;
int input = 1;
int ret = 0;
do
{
printf("******************************\n");
printf("**** 1. add 2. sub ****\n");
printf("**** 3. mul 4. div ****\n");
printf("**** 0. exit ****\n");
printf("******************************\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("输入操作数:");
scanf("%d%d", &x, &y);
ret = add(x, y);
printf("ret=%d\n", ret);
break;
case 2:
printf("输入操作数:");
scanf("%d%d", &x, &y);
ret = sub(x, y);
printf("ret=%d\n", ret);
break;
case 3:
printf("输入操作数:");
scanf("%d%d", &x, &y);
ret = mul(x, y);
printf("ret=%d\n", ret);
break;
case 4:
printf("输入操作数:");
scanf("%d%d", &x, &y);
ret = div(x, y);
printf("ret=%d\n", ret);
break;
case 0:
break;
}
} while (input);
return 0;
}
回调后
#include
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return a / b;
}
void calc(int(*pf)(int, int))
{
int ret = 0;
int x, y;
pintf("输入操作数:");
scanf("%d%d", &x, &y);
ret = pf(x, y);
printf("ret=%d\n", ret);
}
int main()
{
int x, y;
int input = 1;
int ret = 0;
do
{
printf("******************************\n");
printf("**** 1. add 2. sub ****\n");
printf("**** 3. mul 4. div ****\n");
printf("**** 0. exit ****\n");
printf("******************************\n");
scanf("%d", &input);
switch (input)
{
case 1:
calc(add);
break;
case 2:
calc(sub);
break;
case 3:
calc(mul);
break;
case 4:
calc(div);
break;
case 0:
break;
}
} while (input);
return 0;
}
函数实现排序
#define _CRT_SECURE_NO_WARNINGS
#include
#include
int int_cmp(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);
}
int main()
{
int arr[] = { 1,3,5,6,8,2,4 };
int i = 0;
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
非常感谢您的阅读,多多关注呀,后面我也会尽心尽力为大家带来优质好文的