0%

C语言指针笔记

我挑了一些自己在学习C语言指针时觉得需要整理的细化知识点,将它们整理成以下的笔记。因为完全是自学的别问我上C语言课程的时候在干什么,反正不是在偷懒<(ˉ^ˉ)>,所以主要通过琢磨例题和实践编写来掌握和巩固细化的知识点(/ω\)。


指针变量作为函数参数

例题:

输入两个不相等的整数,把这两个整数按照先大后小的顺序输出。用函数处理,而且用指针类型的数据作函数参数。

程序:

#include<stdio.h>
int main(void)
{
void swap(int *X1,int *Y1); //对swap函数进行声明
int x,y;
printf("输入两个不相等的整数:");
scanf("%d%d",&x,&y);
int *X2,*Y2;
X2=&x;
Y2=&y;
if(x<y)
{
swap(X2,Y2); //调用swap函数
}
printf("max=%d\nmin=%d\n",*X2,*Y2);
return 0;
}

void swap(int *X1,int *Y1) //对swap函数进行定义
{
int temp;
temp=*X1;
*X1=*Y1;
*Y1=temp;
}

运行结果:

输入两个不相等的整数:56 89
max=89
min=56

在对swap函数进行定义的过程中,不能将temp定义为指针变量,即不能如下:

void swap(int *X1,int *Y1)
{
int *temp;
*temp=*X1;
*X1=*Y1;
*Y1=*temp;
}

因为未给temp赋值,所以指针变量temp所指向的单元是不可预见的。


通过指针引用数组元素

  • 在C语言中,数组名不代表整个数组,只代表该数组首元素的地址。

  • 指针已指向一个数组元素时,可以对指针进行以下运算:

    • 加一个整数(用+或+=),如p+1;
    • 减一个整数(用-或-=),如p-1;
    • 自加运算,如p++,++p;
    • 自减运算,如p–,–p。
    • 两个指针相减,如p1-p2(只有p1和p2都指向同一数组中的元素时才有意义)。
  • 两个指针不能相加,如p1+p2是无实际意义的。

例题:

通过指针变量输出整型数组a的10个元素。

程序:

#include<stdio.h>
int main(void)
{
int *x,i,a[10];
printf("输入10个整数:");
x=a;
for(i=0;i<10;i++)
{
scanf("%d",x++);
}
x=a;
for(i=0;i<10;i++)
{
printf("%d\t",*(x++));
}
return 0;
}

运行结果:

输入10个整数: 0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9

用数组名作函数参数

  • 实参数组名代表该数组首元素的地址,而形参是用来接收从实参传递过来的数组首元素的地址。因此,形参是一个指针变量。实际上,C编译都是将形参数组名作为指针变量来处理的。

  • C语言调用函数时虚实结合的方法都是采用”值传递“方式,当用变量名作为函数参数时传递的是变量的值,当用数组名作为函数参数时传递的是地址。

  • 实参数组名代表一个固定的地址,或者说是指针常量,但形参数组名并不是一个固定的地址,而是按指针变量处理。

  • 在函数调用进行虚实结合后,形参的值就是实参数组首元素的地址。在函数执行期间,它可以再被赋值。例如:

    void fun(arr[],int n)
    {
    printf("%d\n",*arr);
    arr+=3; //形参数组名可以被赋值
    printf("%d\n",*arr);
    }

例题:

将一个数组中的所有元素按相反顺序排列。

程序:

#include<stdio.h>
int main(void)
{
void inv(int p[],int x);
int a[10]={3,7,9,11,5,21,2,1,8,4};
printf("The original array:\n");
int i;
for(i=0;i<10;i++)
{
printf("%d\t",a[i]);
}
printf("\n");
inv(a,10);
printf("The array has been inverted:\n");
for(i=0;i<10;i++)
{
printf("%d\t",a[i]);
}
return 0;
}

void inv(int p[],int x)
{
int y;
int z=(x-1)/2;
int n;
int temp;
for(y=0;y<=z;y++)
{
n=x-1-y;
temp=p[y];
p[y]=p[n];
p[n]=temp;
}
}

运行结果:

The original array:
3 7 9 11 5 21 2 1 8 4
The array has been inverted:
4 8 1 2 21 5 11 9 7 3

指向二维数组元素的指针变量

  • 在内存中,二维数组的分布是一维线性的

例题:

有一个3×4的二维数组,要求用指向元素的指针变量输出二维数组各元素的值。

程序:

#include<stdio.h>
int main(void)
{
int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int *p;
for(p=a[0];p<a[0]+12;p++)
{
if((p-a[0])%4==0)
{
printf("\n");
}
printf("%d\t",*p);
}
return 0;
}

运行结果


1 3 5 7
9 11 13 15
17 19 21 23

指向由多个元素组成的一维数组的指针变量

例题:

输出二维数组任一行任一列元素的值。

程序:

#include<stdio.h>
int main(void)
{
int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int (*p)[4],i,j; //指针变量p指向包含4个整型元素的一维数组
printf("输入行和列:");
scanf("%d%d",&i,&j);
p=a;
printf("a[%d,%d]=%d",i,j,*(*(p+i)+j));
return 0;
}

运行结果:

输入行和列:2 1
a[2,1]=19

从int (*p)[4]可以看出,p只能指向一个包含4个元素的一维数组,不能指向一维数组中的某一元素,p的值是该一维数组的起始地址。


通过指针引用字符串

  • C语言对字符串常量是按字符数组处理的,在内存中开辟一个字符数组用来存放该字符串常量,但是这个字符数组使没有名字的,因此不能通过数组名来引用,只能通过指针变量来引用。
  • 在内存中,字符串的最后被自动加了’\0’。

例题:

将字符串a复制为字符串b,然后输出字符串b,用指针变量来处理。

程序:

#include<stdio.h>
int main(void)
{
char a[]="https://www.nimitiz.cn";
char b[20];
int i;
for(i=0;*(a+i)!='\0';i++)
{
*(b+i)=*(a+i);
}
*(b+i)=0;
for(i=0;b[i]!='\0';i++)
{
printf("%c",b[i]);
}
return 0;
}

运行结果:

https://www.nimitiz.cn

字符指针作函数参数

例题:

用函数调用实现字符串的复制。

程序:

#include<stdio.h>
int main(void)
{
void copy_string(char from[],char to[]);
char a[]="Linux";
char b[]="Unix";
printf("string a=%s\nstring b=%s\n",a,b);
printf("\ncopy string a to string b:\n");
char *A=a;
char *B=b;
copy_string(A,B); //实参为字符指针变量
printf("string a=%s\nstring b=%s\n",a,b);
return 0;
}

void copy_string(char from[],char to[]) //形参为字符数组
{
int i=0;
while(from[i]!='\0')
{
to[i]=from[i];
i++;
}
to[i]='\0';
}

运行结果:

string a=Linux
string b=Unix

copy string a to string b:
string a=Linux
string b=Linux

使用字符指针变量和字符数组的比较

  • 字符数组由若干个元素组成,每个元素中存放一个字符,而字符指针变量中存放的是字符串第1个字符的地址
  • 可以对字符指针变量赋值,但不能对数组名赋值。
  • 编译时为字符数组分配若干个存储单元以存放各元素的值,而对字符指针变量只分配一个存储单元。
  • 指针变量的值可以改变,而字符数组名代表数组首元素的地址,不能改变。
  • 可以对字符数组中各元素再赋值,但不能对字符指针变量指向的字符串常量再赋值。

用函数指针变量调用函数

例题:

用函数求整数a和b中的大者。

程序:

#include<stdio.h>
int main(void)
{
int max(int,int); //对max函数进行声明
int (*p)(int,int); //定义指向函数的指针变量p
int a,b,c;
p=max;
printf("输入两个不相等的整数:");
scanf("%d%d",&a,&b);
c=(*p)(a,b);
printf("max=%d",c);
return 0;
}

int max(int x,int y) //对max函数进行定义
{
int z;
if(x>y)
{
z=x;
}
else
{
z=y;
}
return z;
}

运行结果:

输入两个不相等的整数:67 32
max=67

定义和使用指向函数的指针变量

例题:

输入两个整数,然后选择0或1,选择0时调用max函数,输出二者中的大数;选择1时调用min函数,输出二者中的小数。

程序:

#include<stdio.h>
int main(void)
{
int (*p)(int,int);
int max(int X,int Y);
int min(int x,int y);
int a,b,z,Z;
printf("输入两个不相等的整数:");
scanf("%d%d",&a,&b);
printf("选择0或1:");
scanf("%d",&z);
if(z==0)
{
p=max;
Z=(*p)(a,b);
printf("max=%d",Z);
}
if(z==1)
{
p=min;
Z=(*p)(a,b);
printf("min=%d",Z);
}
return 0;
}

int max(int X,int Y)
{
int K;
if(X>Y)
{
K=X;
}
else
{
K=Y;
}
return K;
}

int min(int x,int y)
{
int K;
if(x<y)
{
K=x;
}
else
{
K=y;
}
return K;
}

运行结果:

输入两个不相等的整数:34 12
选择010
max=34
输入两个不相等的整数:45 12
选择011
min=12
  • 对指向函数的指针变量不能进行算术运算,如p++、p–等运算是无意义的。

返回指针值的函数

例题:

有3个学生,每个学生有4门课程的成绩。要求在输入学生序号以后,输出该学生的全部成绩。用指针函数来实现。

程序:

#include<stdio.h>
int main(void)
{
int *search(int (*pointer)[4],int n);
int source[3][4]={{89,78,80,76},{67,90,56,70},{91,80,90,75}};
printf("输入学生序号:");
int num;
scanf("%d",&num);
int *p;
p=search(source,num);
int i;
for(i=0;i<4;i++)
{
printf("%d\t",*(p+i));
}
return 0;
}

int *search(int (*pointer)[4],int n)
{
int *pt;
pt=*(pointer+n);
return pt;
}

运行结果:

输入学生序号:1
67 90 56 70

定义和使用指针数组

指针数组中的每一个元素都存放一个地址,相当于一个指针变量。

指针数组比较适合用来指向若干个字符串,使字符串处理更加方便灵活。

例题:

将若干个字符串按字母顺序由小到大输出。

程序:

#include<stdio.h>
#include<string.h>
int main(void)
{
void sort(char *name[],int n);
void print(char *name[],int n);
char *name[]={"Linux","Windows","Android","Unix"}; //定义指针数组,它的元素分别指向4个字符串
int n=4;
sort(name,n); //调用sort函数,对字符串排序
print(name,n); //调用print函数,输出字符串
return 0;
}

void sort(char *name[],int n)
{
char *temp;
int i,j,k;
for(i=0;i<n-1;i++) //用选择法排序
{
k=i;
for(j=i+1;j<n;j++)
{
if(strcmp(name[k],name[j])>0)
{
k=j;
}
}
if(k!=i)
{
temp=name[i];
name[i]=name[k];
name[k]=temp;
}
}
}

void print(char *name[],int n)
{
int i;
for(i=0;i<n;i++)
{
printf("%s\n",name[i]);
}
}

运行结果:

Android
Linux
Unix
Windows

指向指针数据的指针变量

例题:

有一个指针数组,其元素分别指向一个整型数组的元素,用指向指针数据的指针变量,输出整型数组各元素的值。

程序:

#include<stdio.h>
int main(void)
{
int a[5]={1,3,5,7,9};
int *b[5]={&a[0],&a[1],&a[2],&a[3],&a[4]};
int **p;
p=b;
int i;
for(i=0;i<5;i++)
{
printf("%d\t",**p);
p++;
}
return 0;
}

运行结果:

1       3       5       7       9

常见指针变量的定义

定义 含义
int *p; p 可以指向 int 类型的数据,也可以指向类似 int arr[n] 的数组
int **p; p 为二级指针,指向 int * 类型的数据
int *p[n]; p 为指针数组,可以理解为 int *(p[n]);
int (*p)[n]; p 为二维数组指针
int *p(); p 是一个函数,它的返回值类型为 int *
int (*p)(); p 是一个函数指针
  • 指针变量可以进行加减运算,例如 p++、 p+i、 p-=i。指针变量的加减运算并不是简单的加上或减去一个整数,而是跟指针指向的数据类型有关。

  • 使用指针变量之前一定要初始化,否则就不能确定指针指向哪里,如果它指向的内存没有使用权限,程序就会崩溃。对于暂时没有指向的指针,应赋值 NULL。

  • 两个指针变量可以相减。如果两个指针变量指向同一个数组中的某个元素,那么相减的结果就是两个指针之间相差的元素个数。


在C语言指针方面,自己觉得需要整理的细化知识点就是这些了,如有错误,请在评论区多多指教o(^▽^)o。