https://www.bilibili.com/video/BV1cx4y1d7Ut?spm_id_from=333.788.videopod.episodes&vd_source=e8984989cddeb3ef7b7e9fd89098dbe8&p=107
本篇为贺宏宏老师C语言教程指针部分笔记整理
//.c文件
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
//8-1 什么是指针
//指针:就是地址!
//指针:就是地址!
//指针:就是地址!
int main()
{
int a = 10; //4个字节
int b = 20;
&a; //获取a的地址
&b; //获取b的地址
//printf("a的地址=%p,b的地址=%p\n",&a,&b);//%p:输出地址(指针),以16进制进行输出
printf("a的地址=%d,b的地址=%d\n",&a,&b);
return 0;
}
// 8-2 指针变量
int main()
{
int a = 10;
int b = 20;
int *p = &a; //一个int地址(指针)赋值给一个int指针变量
//获取a的地址,int &p = &a;(int &p C++引用) int *p = &a;
p = &b; //把b的地址赋值给p //此处不能用*p了,*p的含义是引用,一词多义
char c;
double d;
char *p1 = &c;
double *p2 = &d;//指针的类型要根据变量的类型进行匹配
return 0;
}
// 8-3 使用指针变量
int main()
{
int a = 10;
printf("%d,%d\n",a,&a);//a的值,a的地址
int *p = &a;
printf("%d,%d,%d\n",*p,p,&p);//p指向的变量a的值,a的地址,p的地址
return 0;
}
// 8-4 &的多个作用
// &的作用:1.按位与 例如4&3 2.取地址 例如 &a 3.C++的引用
//&变量名:获取该变量的地址(指针),&:取地址符(号);这里的&是个单目运算符
//4&3:按位与,这里的&是个双目运算符,有两个变量
int main()
{
int a = 10;
int b = 20;
int c = 4 & 3;//按位与 100 & 011 = 000
printf("%d\n",c);
printf("%p,%p,%p\n",&a,&b,&c);
printf("%p,%p,%p\n",&a&b);//按位与
int& d = a;//C++的引用,相当于a有一个别名叫d了;与其他两种用法的不同在于这个&前面有数据类型
return 0;
}
//8-5 指针应用(指针最重要的部分) Swap交换数据(两个错误示例)
//交换两个变量的值(写成函数)
void Swap_err1(int a, int b)//没有交换成功,错误
{
int tmp = a;
a = b;
b = tmp;
printf("%d %d",&a,&b);
}
void Swap_err2(int *p1, int *p2)//没有解引用,交换失败
{
int *tmp = p1;
p1 = p2;
p2 = tmp;
}
//8-6 指针应用 Swap交换数据2
//总结:一个函数A通过调用函数B,来修改A中变量的值:
//: 1.必须传指针; 2.B中必须解引用
void Swap(int *p1,int *p2)
{
int tmp;
tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int main()
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d %d",&a,&b);
printf("交换前=%d,%d\n",a,b);
Swap(&a,&b);//交换a,b两个值
printf("交换后=%d,%d\n",a,b);
return 0;
}
// 8-7 通过指针返回多个值
//C语言怎么返回两个值?
double Fun(int a, int b, int c)
{
int d = b * b - 4 * a * c;
double x1, x2;
x1 = (-b + sqrt(d))/(2 * a);
x2 = (-b - sqrt(d))/(2 * a);
return x1; // C语言一般只能返回0个或1个值
}
double Fun(int a, int b, int c, double *x1,double *x2)
{
int d = b * b - 4 * a * c;
double x1, x2;
*x1 = (-b + sqrt(d))/(2 * a);
*x2 = (-b - sqrt(d))/(2 * a);
return 2; //2个根
}
int main()
{
double x1;
double x2;
Fun(4,5,1,&x1,&x2);
printf("%lf,%lf\n",x1,x2);
}
//8-9 指针指向数组元素
//问题1:指针如何指向这个数组的元素
//问题2:arr名字
//一维数组arr的名字arr表示整个数组只在如下情况:
//1.在定义数组的同一个函数中求sizeof.例如int arr[10]; sizeof(arr) -> 40,因为int是4个字节
//2.在定义数组的同一个函数中&arr+1表示&arr的地址加一整个数组的大小,例如int arr[10],&arr,&arr+1 = &arr+40
//其他情况,arr都表示数组的起始地址
int main()
{
int arr[10] = {1,3,5,7,9,11,13,15,17,19};
//int* p = &arr[0];//第一个元素int的地址
int *p = arr;//和上一行等价
printf("%d,\n%d\n",*p,arr[0]);
printf("%d,\n%d,\n%d\n",&arr,sizeof(arr),&arr+1);
return 0;
}
//8-10 指针的加法运算
//指针的算数运算:前提是这个指针指向一个数组,同时程序应该保证不越界
//p+整数,p++,++p合法
int main()
{
int arr[10] = {1,3,5,7,9,11,13,15,17,19};
//int* p = &arr[0];//第一个元素int的地址
int *p = arr;//和上一行等价
printf("%d ",*p);
//通过指针输出(访问)数组的所有元素
for(int i = 0; i < 10; i++, p++)
{
printf("%d ",*p);
}
return 0;
}
//8-11指针的减法运算
//指针的算数运算:前提是这个指针指向一个数组,同时程序应该保证不越界
//p+整数,p++,++p合法
int main()
{
int arr[10] = {1,3,5,7,9,11,13,15,17,19};
//int* p = &arr[0];//第一个元素int的地址
int *p = &arr[9];//和上一行等价
int num = sizeof(arr);
printf("%d\n",num); // sizeof(arr)可是40哦,不是10哦,因为int表示4个字节哦。
for(int i = 0; i < 10; i++)//所以这里不能写成i < sizeof(arr),这样就循环40次了。超过10就越界,要出错了
{
printf("%d ",*p--);
}
}
//8-12通过指针引用数组元素
int main()
{
int a[10];
int i;
int *p = a;
printf("please enter 10 integer numbers:");
for(i = 0; i < 10; i++)
scanf("%d", &a[i]);
for(i = 0; i < 10; i++)
printf("%d ",a[i]);
printf("\n");
return 0;
}
//8-13 指针的关系运算
//<,> >= , <=, !=,前提是必须指向同一个数组,绝对不可以操作不同的数组
// 错误用法:在不同的数组了,返回值为0
int main()
{
int a = 10;
int b = 20;
int *p = &a;
printf("%d\n",*(p+1));//错误的应用
int *q = &b;
}
//从头到尾输出数组
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
for(int *p = arr;p!= &arr[10];p++)//标准规定可以使用尾后(尾巴的后面:此处是指数组最后一位的下一处地址)地址(指针)
printf("%d ",*p); //输出1 2 3...
//或者
/*
for(int *p = arr; p != &arr[10]; p++)
printf("%d ",*p);
*/
//或者
/*
for(int *p = arr; p <= &arr[9]; p++)
printf("%d ",*p);
*/
return 0;
}
//8-15 指针在数组中的错误应用
//常见的错误:越界错误
int main()
{
int a[10];
int i;
int *p;
p= a;
printf("please enter 10 integer numbers:");
for(i = 0; i < 10; i++)
scanf("%d", p++); //这里p的指针已经到数组的最后了(p已经到达a的尾后指针),改进办法:p = a;(把p重新赋值),下一行
p = a;
for(i = 0; i < 10; i++,p++)//这里p指针再往后就不是数组内的数了,就是空的地方了,输出的数为随机的数值
printf("%d ",*p);
printf("\n");
return 0;
}
8-16
//8-16 数组作为参数传递:数组名仅仅表示数组首元素的地址
//传数组名+数组长度
//示例1.输出数组的所有元素
//p:数组的起始地址,n:元素的个数
void Show (int *p, int n)
{
for(int i = 0; i < n; i++)
{
printf("%d ",p[i]);
}
}
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
Show(arr,sizeof(arr)/sizeof(arr[0]));//数组元素个数=数组长度/数组每一个元素的长度(这里用第一个元素的长度指代了)
return 0;
}
//示例2.将数组a中n个整数按相反顺序存放
void inv(int *x, int n) //x数组的起始地址,n元素个数
{
int tmp;
//把x当作数组名来操作:(更推荐使用这种方法)
// for(int i = 0, j = n-1; i < j; i++, j--)//i往后走,j往前走
// {
// tmp = x[i];
// x[i] = x[j];
// x[j] = tmp;
// }
//把x当作指针来操作:
for(int i = 0, j = n-1; i < j; i++, j--)
{
tmp = *(x+i);
*(x+i) = *(x+j);
*(x+j) = tmp;
}
}
void Show (int *p, int n)
{
for(int i = 0; i < n; i++)
{
printf("%d ",p[i]);
}
}
int main()
{
int arr[] = {1,3,5,7,9,11,13,15,17,19};
inv(arr,sizeof(arr)/sizeof(arr[0]));
Show(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
把x当作数组名来操作:
把x当作指针来操作:
示例3
5个数字至少需要4次遍历:
第一次:
将第一个数字与剩下的最小值进行比较:
如果第一个数字小于剩下数字的最小值,顺序不变;
如果第一个数字大于剩下数字的最小值,将剩下数字的最小值与第一个数字进行交换。
第二次:
将第二个数字与剩下的最小值进行比较:
如果第二个数字小于剩下数字的最小值,顺序不变;
如果第二个数字大于剩下数字的最小值,将剩下数字的最小值与第二个数字进行交换。
第三次:
将第三个数字与剩下的最小值进行比较:
如果第三个数字小于剩下数字的最小值,顺序不变;
如果第三个数字大于剩下数字的最小值,将剩下数字的最小值与第三个数字进行交换。
第四次:
将第四个数字与剩下的最小值进行比较:
如果第四个数字小于剩下数字的最小值,顺序不变;
如果第四个数字大于剩下数字的最小值,将剩下数字的最小值与第四个数字进行交换。
第五次:
将第五个数字与剩下的最小值进行比较:
如果第五个数字小于剩下数字的最小值,顺序不变;
如果第五个数字大于剩下数字的最小值,将剩下数字的最小值与第五个数字进行交换。
//示例3.用指针方法对10个整数按由大到小顺序排序(选择排序法)
//选择法排序:每次从待排序的数中找最小值和待排序的第一个值进行交换,直到全部有序
//arr:数组起始地址,n:元素个数
//下标法。优先推荐使用下标法,指针法容易出错
void SelectSort1(int* arr, int n)
{
int k;
int tmp;
for(int i = 0; i < n-1; i++)
{
k = i;//这里要提前给k赋值一下
for(int j = i+1; j < n; j++)
{
if(arr[j] < arr[k]) //指针方式:*(arr+j) < *(arr+k)
{
k = j;
}
}
if(arr[k] != arr[i])//这里写k!=i就行了
{
tmp = arr[i];//指针方式:*(arr+i)
arr[i] = arr[k];//指针方式:*(arr+i) = *(arr+k)
arr[k] = tmp;//指针方式:*(arr+k)
}
}
}
//指针方式:
void SelectSort(int* arr, int n)
{
int k;
int tmp;
for(int i = 0; i < n-1; i++)
{
k = i;//这里要提前给k赋值一下
for(int j = i+1; j < n; j++)
{
if(*(arr+j) < *(arr+k))
{
k = j;
}
}
if(k != i)
{
tmp = *(arr+i);
*(arr+i) = *(arr+k);
*(arr+k) = tmp;
}
}
}
void Show (int *p, int n)
{
for(int i = 0; i < n; i++)
{
printf("%d ",p[i]);
}
}
int main()
{
int arr[] = {10,3,65,7,69,181,193,15,157,19};
Show(arr,sizeof(arr)/sizeof(arr[0]));
printf("\n");
SelectSort(arr,sizeof(arr)/sizeof(arr[0]));
Show(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}