Auto Leaders控制组——C语言指针笔记
指针的基础知识
指针和指针变量
指针:在内存中,每个内存单元都有对应的内存地址,我们可以依据内存地址找到内存单元(寻址),这个地址就是指针。它可以是任何类型,包括整型、浮点型、字符型、结构体等。
指针变量:用来存储某个内存单元的地址的变量。它是指向某种特定类型的指针
地址与指针
指针相对于一个内存单元来说,指的是单元的地址,该单元的内容里面存放的是数据。在 C 语言中,允许用指针变量来存放指针,因此,一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。
指针的定义
格式:数据类型* 变量名(intp,int p,int p,int * p,intp,q等多种形式都是正确的,p是指针变量,它的值是某个字符变量的地址)
在64位系统中指针变量占用8个字节
在32位系统中指针变量占用4个字节
指针和取地址符
int a=1;
int* p;//定义指针变量p
p=&a;//使p获得a的地址(p指向a)
printf("%u\n",p);
printf("%u\n",&a);
printf("%d\n",*p)l;
printf("%d\n",a);
取地址符:&
用法是加在变量名的左边,作用是取出变量的地址(返回变量的内存地址)
例如:&a=3396336628
指针:指针类型变量名
取值运算符:
可以取出指针所指向的变量(访问指针指向的变量)
例如:*p=1
运行上述代码
p=3396336628
&a=3396336628
*p=1
a=1
通过运行结果我们可以发现
在结果上
*p=a
p=&a
指针变量的赋值和运算
对于指针变量我们无法直接进行赋值
如果我们输入
int*p=100;
此时系统会发生报错
但我们可以进行强转
int*p=(int*)100;
此时p=100
我们一般对指针变量所指向的变量赋值
如
int a=0;
printf("a=%d\n",a)
int*p=&a;
*p=1;
printf("a=%d *p=%d",a,*p);
运行结果为
a=0
a=1 p=1
在该代码中p=1表示另p指向的变量等于1,此时*p=1与a=1是等价的
指针变量之间是无法进行乘除的
但是可以进行加减法运算
例如
int*p1;
int*p2;
printf("%u %u\n",p1);
printf("%u\n",p2);
printf(“p1-p2=%d”,p1-p2);
p1=3396336632
p2=3396336628
p1-p2=1
我们很容易发现3396336632-3396336628的值应该是4但是程序却显示为1
这是因为指针变量与指针变量的减法代表着两个变量之间的步长数,由于int类型占四个字节所以int类型的指针变量步长为四,两者的差值n代表着相隔n个同类型指针变量(如果指针变量的类型为char则步长为1,对于其他类型步长同样等于占用的字节数)
int*p1;
printf("%u %u\n",p1);
p1++;
printf("%u %u\n",p1);
p1=3396336628
p1=3396336632
如果指针变量加或减一个常数则相应的地址会变化n*步长
多级指针
我们可以对指针变量再次进行取地址运算
此时只需要在指针变量名前加*
int a=1;
int *p=&a;
int **q=&p;
此时指针变量q的值即为指针变量p的地址
*q即为p的值即为a的地址
**q即为a的值
指针与数组
数组与指针变量
首先在数组中每一个元素都是相连的
例如
int arr[5]={'0','1','2','3','4','5','6'};
int*p=arr;
int*p0=&arr[0];
int*p1=&arr[1];
int*p2=&arr[2];
int*p3=&arr[3];
int*p4=&arr[4];
int*p4=&arr[5];
printf("p=%u\n"p):
printf("p0=%u\n"p0):
printf("p1=%u\n"p1):
printf("p2=%u\n"p2):
printf("p3=%u\n"p3):
printf("p4=%u\n"p4):
printf("p5=%u\n"p5):
p=3396336632
p0=3396336632
p1=3396336636
p2=3396336640
p3=3396336644
p4=3396336648
p5=3396336652
我们注意到p和p0是相等的,即当用指针指向数组名时地址是取的数组第一项元素的首地址,并且在同一数组中相邻变量相差的距离均为一个步长
我们可以对其进行运算
int arr[5]={'0','1','2','3','4','5','6'};
int*p=arr;
int*p0=&arr[0];
int*p1=&arr[1];
int*p2=&arr[2];
int*p3=&arr[3];
int*p4=&arr[4];
int*p4=&arr[5];
printf("*p0=%d\n"p0):
printf("*p1=%d\n"*p1):
printf("*p2=%d\n"*p2):
printf("*(p+1)=%d\n"*(p+1)):
printf("*(p+2)=%d\n"*(p+2)):
printf("arr[1]=%d",arr[1]);
printf("arr[2]=%d",arr[2]);
);运行结果为
*p0=0
*p1=1
*p2=2
*(p+1)=1
(p+2)=2
arr[1]=1
arr[2]=2
(要注意的运算优先级比+高所以要注意用())
(p+i)与arr[i]均为i
ps:下标运算符arr[i]的规则其实是将其转化为指针变量再进行运算
即为arr[i]和i[arr]是等价的都是转化为inta=arr+i
这也是在很多情况下用指针进行运算效率会比较高的原因
数组指针和指针数组
指针数组
int* pn 是一个指针, , int* pc[3] 是一个指针数组。
指针数组本质上就是存放着指针的数组
例如
int n1[2]={1,11,111};
int n2={2,22,222};
int n3={3,33,333};
int *p[2];
p[0]=n1;
p[1]=n2;
p[2]=n3;
指针数组p[2]分别指向了n1,n2,n3第一项元素的首地址
数组指针
int A[3][3]={0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15};
int(*pA)[3]=A;
int*p=*pA
则pA是A的指针
且pA=0;(pA+1)=4;
p=0;(p+1)=1;
字符串数组
#include <stdio.h>
int main()
{
char str[] = "alniubi";
char* p = str;
while(*p != '\0')
{
*p-=32;
p++;
}
puts(str);
return 0;
}
结果:ALNIUBI;
用指针指向字符串和数组类似
指针参数传递及函数
指针能够在不同函数之间传递值
假如我们给出下列函数
#include <stdio.h>
void swap(int a , int b)
{
int temp = a;
a= b;
b = temp;
}
int main()
{
int a,b;
a = 1;
b = 2;
swap(&a,&b);
printf("a=%d , b=%d",a,b);
return 0;
}
此时a1;b=2;,ab的值并未发生改变
#include <stdio.h>
void swap(int *x , int *y)
{
int temp = *x;
*x= *y;
*y = temp;
}
int main()
{
int a,b;
a = 1;
b = 2;
swap(&a,&b);
printf("a=%d , b=%d",a,b);
return 0;
}
结果为a=2;b=1;变量的值发生了改变
从函数中返回指针
看下列代码:
#include <stdio.h>
int* fun()
{
static int n = 100; //static 保证 n 在第一次被使用完后不被回收
n++
return &n;
}
int main()
{
int* p = fun();
printf("%d",*p);
fun(); //再次调用被调函数
printf("%d",*p);
return 0;
}
结果:100; 101;
const
const会使变量值无法修改
const int p=&i;
会使p是const。但i可修改。
int *const p=&i;
会使p是不可修改,