#define _CRT_SECURE_NO_WARNINGS//所有代码之前都要写一个这个
第八章 指针
概念
指针:就是地址
&变量名:获取该变量的地址(指针),&称为取地址符,%p:输出地址(指针),以十六进制输出
指针变量:保存指针(地址)的变量,(int 型指针变量)
int *p=&a;//一个int型的地址赋值给int指针变量,定义
p=&b,跟上面一个意思,使用
/*char c;
* char *p1=&c;
* double d;
* double *p2=&d;指针类型必须匹配
* *p的含义访问p所指向的变量,解引用,间接访问符
* 输出p和&p含义不同,前者输出指向变量的地址,后者输出p自己的地址
而*p输出的是所指变量的内容
p里的内容是a的地址,p指向的内容是a的内容
*/
用指针加函数交换两个数的值
#include<stdio.h>
void Swap(int* p1, int* p2) {
int temp;
temp = *p1;//交换的是数不是地址,*p才是指向数
*p1 = *p2;
*p2 = temp;
}
int main() {
/*int a, b;
scanf("%d%d", &a, &b);
Swap(&a, &b);
printf("%d %d", a, b);
return 0;*/
int a, b;
int* p1=&a, * p2=&b;//把地址给人家,这步很重要,先加上人家微信啊
scanf("%d%d", p1, p2);
Swap(p1, p2);//传的是a,b的地址
printf("%d %d\n", a, b);
printf("%d %d", *p1, *p2);//两种输出方式都对
return 0;
}
c语言只能返回0个或1个值
用指针解决多个返回值
指针求方程的根
#include<stdio.h>
#include<math.h>
int Fun(int a, int b, int c, double* x1, double* x2) {
int d = b * b - 4 * a * c;
*x1 = (-b + sqrt(d)) / (2 * a);//*x1才是指数
*x2 = (-b - sqrt(d)) / (2 * a);
return 2;//两个根
}
int main() {
double x1, x2;
Fun(3, 5, 1, &x1, &x2);//传地址
printf("%lf %lf", x1, x2);
return 0;
}
指针指向数组
int *p=&arr[0] 等于 int*p=arr//都是指向第一个元素的地址
用指针输出一个数组
#include<stdio.h>
int main() {
int arr[] = { 1,3,5,7 };
int n = sizeof(arr) / sizeof(arr[0]);//求数组长度
//从前往后输出
//int* p = &arr[0];//指针指向数组的第一个地址
//for (int i = 0; i < n; i++) {
// printf("%d ", *p);//输出指针指向的内容
// //printf("%d ",*(p+i));//这么写也行,但我觉得还是地址往后走比较好理解
// p++;//地址往后走一位
//}
//从后往前输出
int* p = &arr[n - 1];
for (int i = 0; i < n; i++) {
printf("%d ", *p);
p--;
}
return 0;
}
指针的关系运算,前提必须在同一个数组,>,<等,两个单独的变量或两个不同的数组不可以比较大小
从头到尾输出数组
#include<stdio.h>
int main() {
//int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//指针输入
int arr[10];
int* p = &arr[0];
//int*p=arr;(同理)
for (int i = 0; i < 3; i++) {
scanf("%d", p);
p++;
}
p = &arr[0];//重新回到第一个元素位置
//p=arr;同理
for (int i = 0; i < 3; i++) {
printf("%d ", *p);
p++;
}
//for (int* p = arr; p != &arr[10]; p++) {//就是10,这叫尾后指针
// printf("%d ", *p);
//}
或者
//for (int* p = arr; p < &arr[10]; p++) {//就是10,这叫尾后指针
// printf("%d ", *p);
//}
return 0;
}
数组作为参数传递,数组名仅仅只是表示数组首元素的地址
传数组要加长度
传整个数组到函数中
#include<stdio.h>
void Show(int* p, int n) {
for (int i = 0; i < n; i++) {
printf("%d ", *p);
//高级版本
//printf("%d", p[i]);//这么写有点6
p++;
}
}
int main() {
int arr[] = { 1,2,3,5 };
int n = sizeof(arr) / sizeof(arr[0]);
Show(arr,n);
return 0;
}
将数组中的n个整数按相反顺序存放
数组,函数,指针,他们仨才是真玩,跟别人都是假玩
#include<stdio.h>
void Inv(int* p, int n) {
int temp;
for (int i = 0, j = n - 1; i < j; i++, j--) {//一个指前一个指后,错位则停止
temp = p[i];
p[i] = p[j];
p[j] = temp;
//用指针的方式写
/*temp = *(p+i);
*(p+i) = *(p+j);
*(p+j) = temp;*/
}
}
void Show(int* p, int n) {//输出交换后的结果
for (int i = 0; i < n; i++) {
printf("%d ", *p);
p++;
}
}
int main() {
int arr[] = { 1,2,3,4,5,6 };
int n = sizeof(arr) / sizeof(arr[0]);
Inv(arr, n);//传的是首地址和长度
Show(arr, n);//同上
return 0;
}
用指针法对十个整数选择法从大到小排序
找到最大的数与最左边交换
#include<stdio.h>
void Pai(int* p, int n) {
//用数组下标做其实更好,道理都一样,写成数组形式就可以了
int i, j;
int index;
int temp;
for (i = 0; i < n - 1; i++) {
index = i;
for (j = i + 1; j < n; j++) {
if (*(p + index) < *(p + j)) {//看好了跟谁比,不是ij比,很重要,但我不明白为啥i不行
index = j;//道理我懂,但我想不通i也是最左边的数啊,也没变过啊
}
}
if (index != i) {//最小的下标变了则交换数
temp = *(p + i);
*(p + i) = *(p + index);
*(p + index) = temp;
}
}
}
void Show(int* p, int n) {
for (int i = 0; i < n; i++) {
printf("%d ", *p);
p++;
}
}
int main() {
int arr[] = { 11,96,48,63,5,4,69,74,56 };
int n = sizeof(arr) / sizeof(arr[0]);
Pai(arr, n);
Show(arr, n);
return 0;
}
通过指针引用多维数组
#include<stdio.h>
int main() {
int arr[3][4];
int(*p)[4] = arr;//3行4列 /*1*/
int* p2 = arr[0]; /*2*/
p = arr + 1;//加一类型不改变 /*3*/
p2 = arr[0] + 1; /*4*/
int x = arr[0][0]; /*5*/
x = arr[0][0] + 1; /*6*/
return 0;//13,24,56三种不同的类型
}
调用函数,输出二维数组
#include<stdio.h>
void Show(int(*p)[4]) {//这个类型记好
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
printf("%d ", p[i][j]);
}
printf("\n");
}
}
int main() {
int arr[3][4] = { 1,2,3,4,5 };//后面会自己补0
Show(arr);
}
通过指针引用字符串
const:不允许修改(其修饰的)内容
const 只能修饰直接右边,eg:const int *p; p可以变,*p不可以
用函数调用实现字符串的复制
字符串和普通数组的区别:字符串可以通过'\0'判断结尾,所以字符串不需要传长度
#include<stdio.h>
#include<string.h>
void Mystrcpy(const char* first, char*end) {//const加不加都可以,加了之后不能修改他的值
int i; //其实就是相当于粘贴而不是剪切
for (i = 0; first[i] != '\0'; i++) {//字符串结束标志'\0'
end[i] = first[i];
}
end[i] = '\0';//给结尾加个末尾标识符,必须加,要不然会输出后面的未赋值的数
}
int main() {
char arr[10] = "abcde";
char brr[10];
Mystrcpy(arr, brr);
//strcpy(brr, arr);(直接用人家写好的就行,把后面的赋值给前面的,加个头文件)
printf("%s", brr);//字符串%s输出就行
return 0;
}
指向函数的指针
函数名相当于函数地址 Max=&Max
#include<stdio.h>
int Max(int a, int b) {
return a >= b ? a : b;//公式,求最大值的意思
}
int main() {
int(*pfun)(int, int);//pfun是指针,函数参数为int,int
pfun = Max;
pfun = &Max;//与上一句同含义
int a, b;
scanf("%d%d", &a, &b);
printf("%d", pfun(a, b));
return 0;
}
指向函数的指针排序,整的挺复杂的,正经复杂
#include<stdio.h>
#include<stdlib.h>
int Cmp_int(const void* vp1, const void* vp2) {//如果是>0,返回前面,<0返回后面
return *(int*)vp1 - *(int*)vp2;//还原本质
}
int Cmp_double(const void* vp1, const void* vp2) {//必须是int型
double tmp= *(double*)vp1 - *(double*)vp2;//因为返回int型,所以要分情况讨论
if (tmp > 0) {
return 1;
}
else if (tmp < 0) {
return -1;
}
else {
return 0;
}
}
int main() {
int str[] = { 2,65,3,8,96 };
double str2[] = { 34.2,34.3,34.4,65.9 };
int len = sizeof(str) / sizeof(str[0]);
int len2 = sizeof(str2) / sizeof(str2[0]);
qsort(str, len, sizeof(str[0]), Cmp_int);//排序函数四个参数:数组,长度,单个元素长度,比较标准
qsort(str2, len2, sizeof(str2[0]), Cmp_double);
for (int i = 0; i < len; i++) {
printf("%d ", str[i]);
}
printf("\n");
for (int i = 0; i < len2; i++) {
printf("%lf ", str2[i]);
}
return 0;
}
#include<stdio.h>
#include<stdlib.h>
int main() {
动态内存分配:数组里的容量<1024*1024=1M,很小
void*:没有类型信息的指针,仅仅是记录地址
使用场景:1.需要大容量内容2.在一个函数创建的内存在别的函数中还需要使用时
malloc:创建内存,需引用stdlib.h,失败返回NULL,成功返回地址
/* *void *p=malloc(1024*1024*10);
* if (p == NULL) {
*printf("申请失败了");
}
*printf("给一个地址");
*/
/*calloc:创建内存,参数有长度和大小,会把每个元素初始化为0
int* arr = (*int)calloc(n, sizeof(int));//100个整型单元
for (int i; i < n; i++) {
arr[i] = i;
}
*/
/* realloc:修改动态内存大小
int n = 10;
int* arr = (int*)malloc(n*sizeof(int));
arr = (int*)realloc(arr, 2 * n * sizeof(int));
for (int i = 0; i < 2 * n; i++) {
arr[i] = i;
}*/
free:释放内存,动态内存申请,用完要释放掉,要不然内存泄漏,可用的内存越来越少,v变慢
return 0;
}