云计算百科
云计算领域专业知识百科平台

C语言:指针部分

笔记是拿来写给自己看的,整理笔记需要耗费大量的时间,需要持之以恒的不断打卡,而不是拿来完成任务的,我在不更新笔记的时候大概率就是在手敲代码巩固不熟练的代码,如果我的笔记能够帮到你我也十分荣幸!加油!共勉!

指针是一种装地址的数据类型

指针分为整型指针,字符型指针,数组型指针,指针的指针等

指针的概念:

在这里插入图片描述
在这里插入图片描述

对于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));
}

指针的指针:

赞(0)
未经允许不得转载:网硕互联帮助中心 » C语言:指针部分
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!