指针变量
指针初始化
指针变量初始化:如果没有初始化,指针是随机值,既野指针。初始化可以让指针变量有明确的指向。
int a = 10;
int *p = &a;//指针初始化
int *p = NULL; //NULL 0号地址 --- 空指针
指针赋值
int * p;
p = NULL;
int a;
int *p;
p = &a;
int *p,q; //p是指针类型 int *
//q是int型
int *p,*q; //此时表示定义了两个 int*类型的变量 p 和q
//注意:
//定义时候的 * 修饰变量名的 表示定义的是一个指针类型的变量
为什么需要地址?
为了实现被调修改主调函数,值传递无法改变主函数中的数据,如果要对数据进行修改,就要用到指针进行地址传递。
指针作为函数的参数
形参:指针类型变量,用来接收实参,实参是要操作的内存空间的地址。
实参:需要修改的变量的地址,被调函数1中一定要有*运算
体会指针,被调修改主调,练习:1.找出两个数中最大值 和 最小值写成函数 2.写swap()函数,实现交换两数的值。
#include <stdio.h>
void add(int n,int m,int *sum)
{
*sum = n + m;
}
void findMaxMin(int n,int m,int *max,int *min)
{
if(n>m)
{
*max = n;
*min = m;
}
else
{
*max = m;
*min = n;
}
}
void Swap(int *a,int *b)
{
int t = *a;
*a = *b;
*b = t;
}
int main(void)
{
int x=5,y=10;
int sum;
int max;
int min;
// add(x,y,&sum);
// printf("%d\n",sum);
// findMaxMin(x,y,&max,&min);
// printf("max = %d\nmin = %d\n",max,min);
Swap(&x,&y);
printf("x = %d\ny = %d\n",x,y);
return 0;
}
形参中的指针类型变量,只需定义需要修改的变量就可以,其他的值如果也用地址来操作就有些多于了,效率也会降低。需要修改的数据,在传入实参时要用取地址&来传入地址。
指针和一维整型数组
int a[5]; 数组名a表示数组首元素的地址,数组名是个常量不能自增自减。
a =>&a[0] a[0]的数据类型是int,&a[0]的数据类型是int*(指针类型)
int *p = a; p指向数组a
指针运算:&取地址,*指针运算(访问运算对象指向的地址)
p+1,p+n,p-1,p-n,p++,p--:表示(+向后,-向前)跳过了一个或n个基类型。
对数组指针进行自加减:
//打印数组
void printArray(int *a,int len)
{
int i = 0;
for (i = 0;i < len ;++i)
{
printf ("a[%d] = %d\n",i,*a++);
// printf ("a[%d] = %d\n",i,a[i]);
// printf ("a[%d] = %d\n",i,i[a]);
// printf ("a[%d] = %d\n",i,*(a+i));
}
}
1. a <=> &a[0]//a[0]的数据类型 -- int型 ,&a[0] 地址的类型 -- int*
int *p = a; //表示 p指向数组a
此时*p等价于a[0],*p 访问指针p指向的地址中的内容。*p <=> a[0]
2.*(p+i) <=> a[i] <=> *(a+i)//a是一个地址,代表首元素首地址,所以a = & a[0] <=> p
a[i] <=> *(a+i)
i[a] <=> *(i+a) //a[i]==i[a];
所以上述代码中所有printf打印的内容都相同。
3.如果p,q,都是地址,则:
p - q //表示差了多少元素(基类型)
两指针相减,必须是同一类型的指针
p + q 是不允许的,会报错,没有意义。
用指针可以实现用迭代的方式实现逆序,排序和查找。
练习:
1. 准备一个数组,找数组中的最大值 ,用指针完成。
2.数组逆序。
3.对数组排序。
下面的代码只要修改主函数就能实现相关功能。
void findMax(int *a,int len)//找最大值
{
int i = 0;
int max = *a;
for (i = 0;i < len;++i)
{
if (*(a+i)>max)
max = *(a+i);
}
return max;
}
void printArray2(int *begin,int *end)//打印
{
while (begin <= end)
printf("%d ",*begin++);
putchar('\n');
}
void revArray(int *begin,int *end)//数组逆序
{
int t;
while(begin < end)//不用等于
{
t = *begin;
*begin=*end;
*end = t;
++begin;
--end;
}
}
void selectSort(int *begin,int *end)//选择排序
{
int *p;
int *q;
for (p = begin;p < end;++p)
{
for (q = p+1;q <= end;++q)
if (*q < *p)
Swap(q,p);
}
}
void bubbleSort(int *begin,int *end)//冒泡排序
{
int *p;
int *q;
for (p = end;p >begin;--p)
{
for (q = begin;q < p;++q)
{
if (*q > *(q+1))
Swap(q,q+1);
}
}
}
void insertSort(int *begin,int *end)//插入排序
{
int *p;
int *q;
for (p = begin+1;p <= end;++p)
{
int t = *p;
q = p;
while (q > begin && t < *(q-1))
{
*q = *(q -1);
--q;
}
*q = t;
}
}
int * binaryFind(int *begin,int *end,int n)//二分查找
{
int *ret = NULL;
int *mid;
while (begin <= end)
{
mid = begin + (end - begin)/2;
if(*mid < n)
end = mid - 1;
else if (*mid > n)
begin = mid +1;
else
{
ret = mid;
break;
}
}
return ret;
}
int main(void)
{
int a[] = {1,5,7,8,4,1,3};
int len = sizeof(a)/sizeof(a[0]);
// printArray2(a,a+len-1);
int max = 0;
findMax(a,5,&max);
printf("max = %d\n",max);
insertSort(a,a+len-1);
// revArray(a,a+len-1);
int n;
scanf("%d",&n);
printArray2(a,a+len-1);
return 0;
}
快速排序
思想:使用分治法的策略来把一个序列分为较小和较大的两个子序列,然后递归地排序两个子序列。快速排序的基本思想可以概括为以下几个步骤:
1.选择基准值:从数组中选择一个元素作为基准值(pivot),通常选择第一个元素、最后一个元素或中间元素。
2.分区操作:重新排列数组,使得所有比基准值小的元素都在基准值的左边,所有比基准值大的元素都在基准值的右边。这个称为分区(partitioning)的过程。
3.递归排序:递归地将上述步骤应用到基准值左边和右边的子数组上。
4.结束条件:当子数组的大小减少到1或0时,递归结束。
理解过程: