最开头先举个例子,后面会有指针的知识点。
以下代码提供运行:
#include<stdio.h>
int main()
{
int value = 10;
int *ptr = &value; // ptr 存储 value 的地址
printf("%d\n", *ptr); // 输出 10,因为 *ptr 解引用了 ptr,获取了 value 的值
*ptr = 20; // 修改 value 的值为 20,因为 *ptr 解引用了 ptr
printf("%d\n", *ptr);
printf("%d\n", value);
printf("%d\n", ptr);
}
*ptr等于某个地址(如&a)时,是将该地址(&a)存储在该指针(*ptr)内,当指针的值改变时该地址所指向的值也会随之改变。
就如以上代码所示当*ptr = 20时,value的值也变为20,而不是原先的10。
知识点
指针的基本概念
1.地址和指针
在c语言中地址称为指针
我们先举个例子
int num;
scanf("%d",&num);
‘&’为取地址运算符,用于取变量的地址,所以&num表示的是num的地址(指针),scanf()函数可以根据该地址,去访问num的存储空间,并且改变num的内容。
又比如
#include<stdio.h>
#include<string.h>
int month(char *s);
int main()
{
int *p,num;
num = 2;
p = #
printf("%d",*p);
}
//输出结果为:2
将num的地址赋值给p,则p指向的地址就是num的地址,可得出结果*p = 2,其中p是地址。
数据类型要和指针变量一致,如上 *p与num的类型必须一致才可被赋值。
2.指针运算符
#include<stdio.h>
#include<string.h>
int month(char *s);
int main()
{
int *p,num;
p = #
*p = 9 ;
printf("%d %d",*p,num);
}
将9赋值给p所指向的内存空间,而其内存空间又是num的内存空间,故num和*p等价。
指针与数组
一维数组
&a[i](i = 0,1 ,2 ,3...... )表示数组a下标为i的数组元素地址。
下面我们来举个例子:
int a[5];
int *pa;
pa = a;//等价于pa = &a[0]
a表示数组首地址
其中a+1的值为&a[1],其他元素以此类推
可以采用pa[i]的方式表示a[i]
诺有如下定义语句
int a[5],i;
int *pa = a;
则有
地址表达式:
&a[i] == a+i == pa+i == &pa[i]。
数组元素的值表达式:
a[i] == *(a+i) == *(pa+i) == pa[i]。
值得注意的是,a为指针常量其值不可变,pa为变量,可变
a++,a = pa都是不行的,但是换成pa就可以。
这里提供一种组合,大家可以根据上面的等价关系进行修改,验证结果
#include<stdio.h>
int main()
{
int a[10];
int *pa = a;
int i;
for(i = 0; i<5;i++)
scanf("%d",a+i);
for(i = 0; i<5;i++)
printf("%d",*(pa+i));
}
还可以等价于:
#include<stdio.h>
int main()
{
int a[10];
int *pa = a;
for(pa = a ; pa < a+10 ; pa++)
scanf("%d",pa);
for(pa = a ; pa < a+10 ; pa++)
printf("%d",*pa);
}
其中的pa代表地址,将a的地址赋值给pa,因此for里算的是地址的取值范围,a+10表示的是a[10]的地址,而不是简单的+1操作。
合并数组
#include <stdio.h>
#define M 5
#define N 7
void fun(int a[], int m, int b[], int n, int c[]);
int main()
{
int arra[M],arrb[N];
int arrc[M+N],k;
int i;
for(i=0;i<M;i++)
scanf("%d",&arra[i]);
for(i=0;i<N;i++)
scanf("%d",&arrb[i]);
fun(arra,M,arrb,N,arrc);
for(k=0;k<M+N;k++)
printf("%d ",arrc[k]);
printf("\n");
return 0;
}
void fun(int a[], int m, int b[], int n, int c[])
{
int i = 0, j = 0, k = 0;
while (i < m && j < n)
{
if (a[i] < b[j])//a[i]等价于*(a+i)
c[k++] = a[i++];
else
c[k++] = b[j++];
}
while (i < m)
c[k++] = a[i++];
while (j < n)
c[k++] = b[j++];
}
上述函数fun()中a[ ]表示的是一个指针,指向函数的首地址及可表示为*a,但在函数内部,我们使用 a[i]
来访问数组中的元素,而不是直接使用 a
。这是因为 a[i]
实际上是 *(a + i)
的简写,表示从起始地址开始偏移 i
个元素后的值。所以,在函数内部,我们比较的是数组中元素的值,而不是它们的地址。
最大最小数
#include <stdio.h>
void max_min(int x[],int n,int *pmax,int *pmin);
int main()
{
int a[10];
int amax,amin;
int i;
for(i=0;i<10;i++)
{
scanf("%d",&a[i]);
}
max_min(a,10,&amax,&amin);
printf("%d %d\n",amax,amin);
return 0;
}
void max_min(int x[],int n,int *pmax,int *pmin)
{
int i ;
*pmax = *pmin = x[0];
for(i = 0 ; i < n ; i++)
{
if(x[i] > *pmax)
*pmax = x[i];
}
for(i = 0 ; i < n ; i++)
{
if(x[i] < *pmin)
*pmin = x[i];
}
}
杂七杂八
while(*p)的意思
while (*p)
是一个条件语句,它的含义是“只要指针 p
所指向的值不为零”,就执行循环体中的代码。
在 C 语言中,指针 p
可以被用作条件表达式,如果指针 p
不为 NULL(或者说不指向数组或字符串的末尾),条件表达式 *p
就会被解释为真,循环就会继续执行。当指针 p
指向数组或字符串的末尾时,*p
的值将为 0,条件表达式将被解释为假,循环就会终止。
在上述例子中,当指针 p
指向数组的末尾时,即 *p
的值为 0 时,循环将终止,因为条件 while (*p)
不再满足。(来自chatgpt)
*p++和++*p的区别
int arr[] = {1, 2, 3};
int *p = arr;
// ++*p: 先递增 arr[0] 的值,再输出递增后的值
printf("%d\n", ++*p); // 输出 2
// *p++: 先输出 arr[0] 的值,再将指针 p 后移一个位置
printf("%d\n", *p++); // 输出 2
// 现在指针 p 指向了 arr[1]
int arr[] = {1, 2, 3};
int *p = arr;
printf("%d\n", ++*p); // 先递增 arr[0] 的值,arr[0] 变为 2,然后输出 2
printf("%d\n", *p++); // 输出 arr[0] 的值,即 2,然后将指针 p 后移一个位置
printf("%d\n", *p); // p 指向了 arr[1],输出 arr[1] 的值,即 3
这三串代码有一定的关联,第一个先递增arr使其变为arr[1]然后输出
第二个是先输出*p,然后再递增到下一个地址,及第二个的值即为第一个的值,第二个值递增的下一个地址赋值到了第三个。