admin管理员组文章数量:1794759
学习——理解指针(1)
一、内存和指针
1、内存与地址
举个例子,一栋大楼中有许多个房间,如果想要快速的找到一个房间,就需要知道这个 房间的门牌号,这个门牌号就可以理解成这个房间的地址;
在计算机中其实也是把内存划分为⼀个个的内存单元,每个内存单元的⼤⼩取1个字节。
计算机中常⻅的单位(补充):
- ⼀个⽐特位可以存储⼀个2进制的位1或者0;
- 一个字节(byte)等于八个比特位(bit)。
存储信息的内存编号 <==> 地址 <==> 指针
二、指针变量(&与*)
在编写代码时:
int a; 创建了一个整型变量a,向内存中申请了一个整型变量(占4个字节)的空间,每一个字节的内存空间都有它的内存编号。
<1> &(取地址操作符)
通过&(取地址操作符)可以获得一个变量的地址,&a就是a的地址;
有了a的地址,现在需要把地址存起来,这时候就用到了指针变量;
代码语言:javascript代码运行次数:0运行复制int a;
int* b=&a;
这里,b就是一个指针变量,类型是int*,*说明b是一个指针变量,int表示b所指向的对象类型是个整型。
<2> *(解引用操作符)
指针变量存放地址,如果想通过这个地址找到它指向的变量,就需要用到*(解引用操作),即
int a=10;
int* b=&a;
printf("%d",*b);
通过解引用操作,就可以找到指针所指向的变量;
指针变量可以存储一个变量的地址,但如果这个变量是一个指针变量,这是,就会一个新的概念:二级指针
二级指针:存放一级指针地址的变量。
代码语言:javascript代码运行次数:0运行复制int a=10;
int* pa=&a;
int** ppa=&pa;
*pa=a。 **ppa=*pa=a。
三、指针类型的意义
<1> 指针类型不同,通过解引用操作所访问从字节数就不同
例:char*类型的指针解引用操作只访问一个字节,二int*类型访问4个字节;
int a = 1234443; int* p = &a; *p = 0;
int a=1234443; char*pa=(char*)&a; *p=0;
<2> 指针类型不同,指针运算所跳过的字节数也不同
char* 类型指针+1跳过1个字节,而int*类型的指针+1跳过4个字节。
<3>void*指针
void是一个泛型指针,它可以接受任何类型的指针,但是不能进行指针运算和解引用操作。
四、指针运算
<1>指针+-整数
我们知道,数组在内存中是连续存储的,所以,只需要找到一个元素的地址,通过指针+-整数会可以访问数组中所有数据。
代码语言:javascript代码运行次数:0运行复制#include<stdio.h>
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
int i, sz;
int* p = arr;
sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++) {
printf("%d ", *(p + i));
}
return 0;
}
用指针加减整数去实现数组下标访问。
<2>指针-指针
指针-指针的绝对值是两个指针之间的元素个数。
前提:两个指针指向同一块内存空间。
代码语言:javascript代码运行次数:0运行复制#include<stdio.h>
int my_strlen(char* str) {
char* p = str;
while (*str != '\0') {
str++;
}
return str - p;
}
int main() {
char arr[] = "abcd";
printf("%d\n", my_strlen(arr));
return 0;
}
<3>指针关系运算
指针地址大小的比较。
代码语言:javascript代码运行次数:0运行复制int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
int* p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
while (p < arr + sz) {
printf("%d ", *p);
p++;
}
return 0;
}
五、const 修饰指针
当const修饰一个变量时,这个变量就不可以再进行修改;现在,用const修饰一个指针变量,这个指针变量是不是也是不可被修改的呢?
我们知道,指针变量存放的是地址,地址又有所指向的值,所以用const修饰指针变量,是指针变量不可被修改,还是指针所指向的值不可被修改呢?
<1>const 修饰*p
const int *p;
const 放在*的前面(左面)时,const修饰指针所指向的内容,保证指针指向的内容不能通过指针来改变。 但是指针变量本身的内容可变(就是他存储的地址可以改变)。
<2>const 修饰p
int* const p;
const如果放在*的后面(右边),修饰的是指针变量本身,保证了指针变量的内容不能修改(它存储的地址不能改变),但是指针指向的内容,可以通过指针改变。
六、野指针
<1>野指针形成原因
1.指针没有初始化
int* p;
*p=20;
规避:初始化指针;不知道指针该指向哪里,就给指针赋值NULL(空指针)。
NULL 是C语⾔中定义的⼀个标识符常量,值是0,0也是地址,这个地址是无法使用的,读写该地址会报错。
2.指针越界
# include <stdio.h>
int main ()
{
int arr[ 10 ] = { 0 };
int *p = &arr[ 0 ];
int i = 0 ;
for (i= 0 ; i<= 11 ; i++)
{
// 当指针指向的范围超出数组 arr 的范围时, p 就是野指针
*(p++) = i;
}
return 0 ;
}
⼀个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是 越界访问。
3.指针所指向的空间被释放
代码语言:javascript代码运行次数:0运行复制#include <stdio.h>
int* test()
{
int n = 100;
return &n;
}
int main()
{
int*p = test();
printf("%d\n", *p);
return 0;
}
尽量不使用局部变量的地址。
<2>assert断言
指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性
assert(p != NULL );
用来判断指针是否为空指针,如果为空,代码程序终止。
assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报
错终⽌运⾏。这个宏常常被称为“断⾔”。
而如果不再需要assert进行断言
# define NDEBUG
使assert失效,不进行判断。
七、传值调用与传址调用
当你用代码编写一个函数交换两个数的值时
代码语言:javascript代码运行次数:0运行复制void swap1(int x, int y) {
int t;
t = x;
x = y;
y = t;
}
int main() {
int a, b;
scanf("%d%d", &a, &b);
printf("交换前:a=%d, b=%d", a, b);
swap1(a, b);
printf("交换后:a=%d, b=%d", a, b);
return 0;
}
你会发现,这样并没有把a与b的值进行交换;
其实,这样写代码只是将a与b的数值传给了函数swap1的形参,而在函数运行时,会创建两个临时变量x,y用来接收a,b的值,而函数也只是将x,y两个的值交换了,并没有把a和b进行交换;当函数执行完以后,a与b没有进行交换。
实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实
参。
像这种只是把数值传给函数形参的,就是传值调用
那又该怎样实现?
可以将a,b的地址传给函数,这样函数在运行工程中,可以直接通过解引用操作访问a与b,并进行修改
代码语言:javascript代码运行次数:0运行复制void Swap2(int*px, int*py)
{
int tmp = 0;
tmp = *px;
*px = *py;
*py = tmp;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
printf("交换前:a=%d b=%d\n", a, b);
Swap2(&a, &b);
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
传址调⽤:可以让函数和主调函数之间建⽴真正的联系,在函数内部可以修改主调函数中的变量;所 以未来函数中只是需要主调函数中的变量值来实现计算,就可以采⽤传值调⽤。如果函数内部要修改 主调函数中的变量的值,就需要传址调⽤。
应用:strlen的模拟实现
代码语言:javascript代码运行次数:0运行复制int my_strlen(const char * str)
{
int count = 0;
assert(str);
while(*str)
{
count++;
str++;
}
return count;
}
int main()
{
int len = my_strlen("abcdef");
printf("%d\n", len);
return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2024-06-07,如有侵权请联系 cloudcommunity@tencent 删除变量函数内存指针int本文标签: 学习理解指针(1)
版权声明:本文标题:学习——理解指针(1) 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1754744432a1705861.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论