笔记是拿来写给自己看的,整理笔记需要耗费大量的时间,需要持之以恒的不断打卡,而不是拿来完成任务的,我在不更新笔记的时候大概率就是在手敲代码巩固不熟练的代码,如果我的笔记能够帮到你我也十分荣幸!加油!共勉!
指针是一种装地址的数据类型
指针分为整型指针,字符型指针,数组型指针,指针的指针等
指针的概念:
对于64位的系统任何类型的指针大小都为8字节,对于32位的系统任何类型的指针大小都为4字节。
指针保存变量首字节的地址值,p表示的就是i本身。通过p来访问i的值这样的方式称为间接访问。
注释:这里是以32位系统来举例,所以指针容量位4字节。
图解:
使用指针的目的:为了实现在被调函数中去修改主调函数
例:
定义指针需要定要指针指向的地址,否则这种指针称为野指针,野指针会随机储存地址,有些地址不能够进行修改,修改会导致程序运行崩溃,指针标准定义形式:
int main(void)
{
int i=1;
int *p;
p=&i; // 储存指定的地址
printf("%p\\n",p);
char *l;
l=(char *)&i;
printf("%d\\n",*l);
if(*I==1)
{
puts(“little”);
}
else
{
puts(“big”);
}
return 0;
}
通过上面的代码中的强转(char *)可以实现判断使用的设备是小端存储还是大端存储。
!!!用const修饰变量,对变量的修改无法通过直接访问来进行,虽然强调i不能发生变化,但还是能够通过指针间接访问来进行修改。
!!!在指针变量前加const修饰指的是无法通过该指针来修改它所指向的变量。
所以在定义函数的指针变量时,应该考虑指针变量所指向的内容内否被修改,在不能被修改的指针变量前应该加const来修饰。
强行修改会引发编译报错
!!! 在判断两个指针是否相同,应该判断二者保存的地址值是否相同。
输出:yes
!!! 用void类型定义指针,在函数内将指针强转为char型指针,将指针所指向的内容转为单字节字符打印,通过这种方法能够将任意类型的指针所指内容进行输出
数组指针以及指针数组:
数组指针的作用对象是一整个数组,而指针数组是由指针组成的数组。
数组指针能够指向整个数组本身而非数组的首元素,
&a[0]取地址a [0] 表示数组的首元素地址,而&a表示这个数组的地址,二者刚好相同。
要用一个什么样的指针来装&a呢?
int *p的基类型是整型,与&a对应的整型数组类型不同,不能用int *p来装数组的地址
正确写法:
这样指针p的基类型就是长度为10的整型数组,这里*p加括号是因为如果去掉括号编译器会将其辨别为指针数组,即:
证明:
对于一位数组的指针,p+1与p所保存的地址值相差1sizeof基类型个字节,即410=40个字节。
此时p+1变为野指针,指向数组外下一个地址,此时该指针可用于二维数组的换行。
对于二维数组:
对于二维数组a表示含有三行四列元素的数组的首元素(第零行一维数组)的地址值,*a/a[0]表示第零行这个一位数组的首元素a [0][0]的地址值,所以对于二维数组sizeof(a)求的是这整个数组的总字节数,对于int型12元素的二维数组,它总共占48字节;sizeof(*a)求的是这个二维数组第0行4个元素所占的字节数,即为16个字节。
整型指针:
课上练习:
找三个数内的最大值以及最小值:
void maxOrMinOfThreeNumbers(int a,int b,int c ,int *pmax,int *pmin)
{
*pmax=a>b?a:b;
*pmax=c>*pmax?c:*pmax;
*pmin=a<b?a:b;
*pmin=c<*pmin?c:*pmin;
}
int main(void)
{
int a=3,b=1,c=2;
int max;
int min;
maxOrMinOfThreeNumbers(a,b,c,&max,&min);
printf("%d\\n",max);
printf("%d\\n",min);
return 0;
}
用指针调用一个函数就可以获得一个以上的结果
两数交换:
#endif
#if 0
void swap(int *a,int *b)
{
int t=*a;
*a=*b;
*b=t;
}
int main(void)
{
int i=10,j=20;
swap(&i,&j);
printf("%d %d\\n",i,j);
return 0;
}
对指针做加法运算
p+1与p差了一个基类型字节(int型:4字节)
P+1和p差了两个字节。(short型2字节)
总结:
字符型指针:char *s形式
位于栈上的指针保存字符串的首元素地址,指向字符串常量区对应字符串的首元素。通过该指针能够访问指向字符串的内容
!!字符串处在字符串常量区,使用指针对字符串进行修改会导致程序崩溃
对于一维字符型数组的指针练习:
用puts遍历字符串:
void Puts( const char *s)
{
while(*s)
{
putchar(*s++);
}
putchar('\\n');
}
计算字符串的有效长度:
int STRLEN( const char *s)
{
int counter=0;
while(*s)
{
++s;
++counter;
}
return counter;
}
int main(void)
{
char s[100]="hello";
Puts(s);
printf("%d\\n",STRLEN("hello"));
return 0;
}
拷贝:
void Strcpy(char *dest,const char *src)
{
while(*src)
{
*dest++=*src++;
}
*dest=0;
}
标准自定义长度拷贝:
char *Strncpy(char *dest, const char *src,int n)
{
char *ret=dest;
while(*src&&n–)
{
*dest++=*src++;
}
return ret;
}
任意类型拷贝:使用万能指针
void Memcpy(void *dest,void *src,int n) //任意类型拷贝
{
char *p=(char *)dest;
char *q=(char *)src;
while(n–)
{
*p++=*q++;
}
}
标准拼接:
char *Strcat(char *dest,const char *src)
{
char *ret=dest;
while(*dest)
{
dest++;
}
while(*src)
{
*dest++=*src++;
}
*dest=0;
return ret;
}
自定义长度拼接:
void Strncat(char *dest, const char *src,int n)
{
while(*dest)
{
dest++;
}
while(*src&&n–)
{
*dest++=*src++;
}
*dest=0;
}
比较两字符串大小:
int Strcmp(const char *s1,const char *s2 )
{
while(*s1&&*s2&&*s1==*s2)
{
++s1;
++s2;
}
return *s1-*s2;
}
自定义长度比较字符串大小:
int Strncmp(const char *s1,const char *s2,int n)
{
while(*s1==*s2&&*s1&&*s2&&–n)
{
++s1;
++s2;
}
return *s1-*s2;
}
查找值:
int Findchar(const char *s1,const char *s2)
{
int i;
for(i=0;i<=strlen(s1)-strlen(s2);++i)
{
if(Strncmp(s1+i,s2,strlen(s2))==0)
{
break;
}
}
if(i<=strlen(s1)-strlen(s2))
{
return i;
}
return -1;
}
主函数:
int main(void)
{
char s1[100]="hello";
char s2[100];
char s3[100]="world";
char s4[100]="hello! World!";
char s5[100]="World!";
//int ret=Findchar(s4,s5);
//if(ret)
//{
//printf("found!在第=%d个\\n",ret);
//}
//else if(ret=-1)
//{
//printf("error!");
//}
//Strcpy(s2,s1);
//Memcpy(s3,s1,sizeof(s1));
// Strcat(s3,s1);
//printf("%d\\n",Strcmp(s1,s3));
//Strncat(s1,s3+1,3);
// printf("%d\\n",Strncmp(s1,s3,3));
puts(Strcat(s3,s1));
return 0;
}
数组型指针:
一维数组的指针:
一维整型数组的指针:
这里两个单目运算符,结合方向从右向左,先对指针所对应的地址进行修改。p++对地址值进行修改,之后的p表示的是a[1]的值。
区分以下:
这里加括号以后是对a[0]的值进行加一。
一维数组的遍历:
课上代码
遍历打印数组:
#include<stdio.h>
void printArray(int len,int *a)
{
int i;
for(i=0;i<len;++i)
{
printf("%d ",*a++);
}
puts("\\n");
}
求数组所有元素之和:
int sumOfArray(int len,int *a)
{
int sum=0,i;
for(i=0;i<len;++i)
{
sum+=*a++;
}
return sum;
}
逆序:
void verseArray(int len,int *a)
{
int i;
for(i=0;i<len/2;++i)
{
int t=*(a+i);
*(a+i)=*(a+len-i-1);
*(a+len-i-1)=t;
}
}
两数交换
void swapArray(int *a,int *b)
{
int t=*a;
*a=*b;
*b=t;
}
选择排序:
void sortArray(int *a,int len)
{
int i,j;
for(i=0;i<len-1;++i)
{
for(j=i+1;j<len;++j)
{
if(*(a+i)>*(a+j))
{
swapArray(a+i,a+j); ///明确swapArray的参数!!!!!
}
}
}
}
重点:使用返回值为指针的函数写二分查找的代码:
int *binaryFind(int *a,int len,int n) //!!!二分查找不熟练
{
int begin=0;
int end=len-1;
while(begin<end)
{
int mid=(begin+end)/2;
if(*(a+mid)>n)
{
end=mid-1;
}
else if(*(a+mid)<n)
{
begin=mid+1;
}
else
{
return a+mid;
}
}
return NULL;
}
int main(void)
{
int a[]={1,3,2,5,4,7,6,9,8,0};
int len=sizeof(a)/sizeof(*a);
//verseArray(len,a);
//swapArray(a,&a[1]);
//sortArray(a,len);
int n;
scanf("%d",&n);
int *ret=binaryFind(a,len,n);
if(ret)
{
printf("found! value=%d\\n",*ret);
}
else
{
printf("error!");
}
//printArray(len,a);
//printf("%d\\n",sumOfArray(len,a));
return 0;
}
通过修改指针可以更加灵活的实现函数的自定义效果:
–
从a [1] 开始遍历,遍历len-1个元素。
——————————————————————————————————————————————
——————————————————————————————————————————————
将begin和end作为指针优化上面的代码:
遍历:
void printArray(int *begin,int *end)
{
while(begin<=end)
{
printf("%d\\n",*begin++);
}
}
递归遍历
void printArray2(int *begin,int *end) //利用递归
{
if(begin>end)
{
return ;
}
else
{
printf("%d\\n",*begin);
printArray2(begin+1,end);
}
}
交换元素
void swapArray(int *a,int *b)
{
int t=*a;
*a=*b;
*b=t;
}
对于一维整型数组进行逆序:
void reverse(int *begin,int *end)
{
while(begin<end)
{
swapArray(begin++,end–);
}
}
运用递归思想对一维整型数组逆序:
void reverse2(int *begin,int *end)
{
if(begin>end)
{
return;
}
else
{
swapArray(begin,end);
reverse2(++begin,–end);
}
}
重点———快速排序:
void Qsort(int *begin,int *end)
{
if(begin>=end)
{
return ;
}
int *p=begin;
int *q=end;
int t=*begin;
while(p<q)
{
while(p<q&&*q>=t)
{
–q;
}
while(p<q&&*p<=t)
{
++p;
}
swapArray(p,q);
}
swapArray(begin,p);
Qsort(begin,p-1);
Qsort(q+1,end);
}
选择排序:
void choiceSort(int *begin,int *end)
{
for(;begin<end;++begin)
{
int *p;
for(p=begin+1;p<=end;++p)
{
if(*p<*begin)
{
swapArray(begin,p);
}
}
}
}
冒泡排序:
void bubbleSort(int *begin,int *end)
{
for(;end>begin;–end)
{
for(;begin<end;++begin)
{
int *p=begin+1;
if(*p<*begin)
{
swapArray(p,begin);
}
}
}
}
二分查找:
int *binaryFind(int *begin,int *end,int n)
{
int *mid=(end-begin)/2+begin;
if(n<*mid)
{
end=mid-1;
}
else if(n>*mid)
{
begin=mid+1;
}
else
{
return mid;
}
return NULL;
}
主函数:
int main(void)
{
int a[]={2,7,5,9,3,1,4,6,10,8};
int len=sizeof(a)/sizeof(*a);
//printArray(a, a + len – 1);
//printArray2(a,a+len-1);
//reverse(a,a+len-1);
//reverse2(a,a+len-1);
Qsort(a,a+len-1);
//choiceSort(a,a+len-1);
bubbleSort(a,a+len-1);
//int *ret=binaryFind(a,a+len-1,5);
//if(ret)
//{
//printf("find,value=%d\\n",*ret);
//}
//else
//{
//printf("error");
//}
//printf("%p\\n",binaryFind(a,a+len-1,5));
printArray(a,a+len-1);
return 0;
}
作业:用递归来进行二分查找:
int *binaryFind2(int *begin, int *end, int n) {
if (begin >= end)
{
return NULL;
}
int *mid = begin + (end – begin) / 2
if (*mid == n)
{
return mid;
}
else if (*mid > n)
{
return binaryFind2(begin, mid, n);
}
else
{
return binaryFind2(mid + 1, end, n);
}
}
二维数组的指针:
求二维数组所有元素之和:
int sumOf2DArray(int (*a)[4],int rows,int cols)
{
int i,sum=0,j;
for(i=0;i<rows;++i)
{
for(j=0;j<cols;++j)
{
sum+=*(*(a+i)+j);
}
}
return sum;
}
void swap(int *a,int *b)
{
int t=*a;
*a=*b;
*b=t;
}
一维数组逆序:
void reverse(int *begin,int *end)
{
while(begin<end)
{
swap(begin++,end–);
}
}
二维数组行逆序:
void reverse2DArray(int (*a)[4],int rows,int cols)
{
int i,j;
for(i=0;i<rows;++i)
{
reverse((*(a+i)),(*(a+i)+cols-1));
}
}
二维数组遍历打印:
void print2Darray(int (*a)[4],int rows,int cols)
{
int i,j;
for(i=0;i<rows;++i)
{
for(j=0;j<cols;++j)
{
printf("%2d ",*(*(a+i)+j));
}
puts("\\n");
}
}
主函数:
int main(void)
{
int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int rows=sizeof(a)/sizeof(*a);
int cols=sizeof(*a)/sizeof(**a);
reverse2DArray(a,rows,cols);
print2Darray(a,rows,cols);
//printf("%d\\n",sumOf2DArray(a,rows,cols));
}
评论前必须登录!
注册