事业单位网站建设方案,建地方的网站前景,网络营销与策划形考任务四答案,wordpress 万网内存和地址
讲解这个之前要先明确指针的概念#xff0c;举个例子#xff0c;在居民楼中#xff0c;如果你要找个人并且有他的门牌号#xff0c;是不是就能快速找到他住的房间#xff0c;对应到计算机中#xff0c;cpu处理的数据是需要在内存中读取的#xff0c;内存的…内存和地址
讲解这个之前要先明确指针的概念举个例子在居民楼中如果你要找个人并且有他的门牌号是不是就能快速找到他住的房间对应到计算机中cpu处理的数据是需要在内存中读取的内存的管理也是同房间号一样划分成一个个内存单元每个内存单元就和门牌号一样有一个编号生活中我们把门牌号叫做地址计算机中内存单元的编号也叫做地址c语言中给地址取了一个新名字指针。
所以我们可以理解为 内存单元的编号地址指针
指针变量和地址 取地址操作符
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.h
int main() {int a 10;printf(%p, a);//输出a的地址return 0;
} 看一下运行结果 但int a毫无疑问是占4个字节的a所输出的是a所占4个字节中地址较小的字节
指针变量
我们通过上面的a得到的地址是一个数值那这样的数值就可以放在指针中方便使用
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.h
int main() {int a 10;int* q a;//取出a的地址存放在指针q中return 0;
}
使用指针变量就是一种存放地址的变量存放在其中的值都会被理解为地址
指针的类型
int a 10;
int* q a; q左边写的是int*其中*代表q是一个指针变量*前面的int是说明q指向的是一个int类型的对象 解引用操作符*
将地址保存进指针之后如何取出来使用呢
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.h
int main() {int a 10;int* q a;*q 0;return 0;
} *q的意思就是通过q中存放的地址找到指向的空间*q其实就是a变量了使用*q0就是把a变量改成了0这样对a的修改就多了一种途径能够更灵活的使用。
指针变量的大小
在32位平台地址就是32bit指针变量大小为4个字节
在64位平台地址就是64bit指针变量大小为8个字节
指针变量大小与类型无关在相同平台下大小都是相同的
指针变量类型的意义
指针的解引用
指针变量的类型虽然与大小无关但它还是有意义的它决定了对指针解引用的时候有多大的权限一次能操作几个字符如char*的指针解引用只能访问一个字节int*的指针解引用就能访问4个字节
指针加减整数
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.h
int main() {int a 1;char* q (char*) a;int* w a;printf(a %p\n,a);printf(q %p\n,q);printf(q1 %p\n,q1);printf(w %p\n,w);printf(w1 %p\n,w1);return 0;
}
运行结果如下 可以看到char*类型的指针变量1跳过一个字节int*的指针变量跳过了4个字节这就是指针类型差异带来的变化
const修饰指针
如果希望指针变量不被修改
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.h
int main() {int a 1;//a是可修改的const int w 1;//w是不可修改的return 0;
} 如果加上const再想修改w程序就会直接报错
但如果绕过w使用w的地址去修改w就可以
#include stdio.h
int main()
{const int n 0;printf(n %d\n, n);int*p n;*p 20;printf(n %d\n, n);return 0;
}
const修饰指针变量的时候 const如果放在*左边修饰的是指针指向的内容保证指针指向的内容不能通过指针改变但指针变量本身的内容可变 const如果放在*右边修饰的是指针变量本身保证指针变量的内容不能修改但指针指向的内容可以修改
指针运算
指针加减整数
因为数组在内存中是连续存放的只要知道头元素的地址就能找到后面的全部元素
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.h
int main() {int arr[5] {1,2,3,4,5};
} 下面是一个指针加减整数的例子
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.h
int main() {int arr[10] { 1,2,3,4,5,6,7,8,9,10 };int* p arr[0];int i 0;int sz sizeof(arr) / sizeof(arr[0]);for (i 0; i sz; i){printf(%d , *(p i));//指针整数}return 0;
} 可以看到循环正常输出*pi其实等同与arr【i】
指针减指针
#define _CRT_SECURE_NO_WARNINGS 1
#include stdio.h
int my_strlen(const char* s){const char* p s;while (*p ! \0)p;//最终p指向了\0//s还是指向字符串“abc”首元素a的地址return p - s;//返回的就是\0前的元素个数
}
int main(){printf(%zd\n, my_strlen(abc));return 0;
} 所以可知指针-指针的绝对值是指针和指针之间的元素个数(大地址减去小地址得到的是正数小地址减去大地址得到的是负数
野指针
野指针就是指针指向的位置是不可知的
野指针成因
1.指针未初始化
#include stdio.h
int main(){ int *p;//局部变量指针未初始化为随机值*p 20;return 0;
}
2. 指针越界访问
#include stdio.h
int main(){int arr[10] {0};
int *p arr[0];int i 0;for(i0; i11; i){//当指针指向的范围超出数组arr的范围时p就是野指针*(p) i;}return 0;
}
指针虽然可以指向未知的空间不会报错但是你要是要操作那块空间就有可能会报错因为越界访问了
3. 指针指向的空间释放
#include stdio.h
int* test(){int n 100;return n;
}
int main(){int*p test();printf(%d\n, *p);return 0;
} 如此也能输出100 如何规避野指针
指针初始化
如果明确知道指针指向哪⾥就直接赋值地址如果不知道指针应该指向哪⾥可以给指针赋值NULL.
初始化如下
#include stdio.h
int main()
{int num 10;int*p1 num;int*p2 NULL;return 0;
}
注意指针是否越界 ⼀个程序只能通过指针访问自己申请的空间不能超出范围访问超出了就是越界访问 指针变量不再使用时及时置NULL指针使用之前检查有效性
assert断言 assert.h 头⽂件定义了宏 assert() ⽤于在运⾏时确保程序符合指定条件如果不符合就报 错终止运行。这个宏常常被称为“断⾔”。 assert(p ! NULL); 上⾯代码在程序运⾏到这⼀⾏语句时验证变量 p 是否等于 NULL 。如果确实不等于 NULL 程序 继续运⾏否则就会终⽌运⾏并且给出报错信息提示 assert() 宏接受⼀个表达式作为参数。如果该表达式为真返回值⾮零 assert() 不会产⽣任何作⽤程序继续运⾏。如果该表达式为假返回值为零 assert() 就会报错在标准错误流 stderr 中写⼊⼀条错误信息显⽰没有通过的表达式以及包含这个表达式的⽂件名和行号。
使⽤ assert() 它不仅能⾃动标识⽂件和出问题的行号还有⼀种⽆需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问 题不需要再做断⾔就在 #include assert.h 语句的前⾯定义⼀个宏 NDEBUG
#define NDEBUG
#include assert.h
如果程序⼜出现问题可以移除这条 #define NDBUG 指令就重新启⽤了 assert() 语句。
指针的使用和传址调用
有没有什么问题是非指针不可的呢
#include stdio.h
void Swap1(int x, int y){int tmp x;x y;y tmp;
}
int main(){int a 0;int b 0;scanf(%d %d, a, b);printf(交换前a%d b%d\n, a, b);Swap1(a, b);printf(交换后a%d b%d\n, a, b);return 0;
} 这是一个交换两个整形变量的函数但如果运行的话 并没有任何效果调试看看 我们发现在main函数内部创建了a和ba的地址是0x00cffdd0b的地址是0x00cffdc4在调用 Swap1函数时将a和b传递给了Swap1函数在Swap1函数内部创建了形参x和y接收a和b的值但是 x的地址是0x00cffcecy的地址是0x00cffcf0x和y确实接收到了a和b的值不过x的地址和a的地址不 ⼀样y的地址和b的地址不⼀样相当于x和y是独立的空间那么在Swap1函数内部交换x和y的值 自然不会影响a和b当Swap1函数调⽤结束后回到main函数a和b的没法交换。Swap1函数在使用的时候是把变量本⾝直接传递给了函数这种调⽤函数的⽅式我们之前在函数的时候就知道了这种叫传值调用。 结论实参传递给形参的时候形参会单独创建⼀份临时空间来接收实参对形参的修改不影响实 参。 所以Swap是失败的了。 更改一下 使用指针在main函数中将a和b的地址传递给Swap函数Swap函数里边通过地址间接的操作main函数中的a和b并达到交换的效果 #include stdio.h
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);Swap1(a, b);printf(交换后a%d b%d\n, a, b);return 0;
} 看下结果 我们可以看到实现成Swap2的方式顺利完成了任务这里调用Swap2函数的时候是将变量的地址传递给了函数这种函数调用方式叫传址调用。 传址调用可以让函数和主调函数之间建立真正的联系在函数内部可以修改主调函数中的变量所以未来函数中只是需要主调函数中的变量值来实现计算就可以采用传值调用。如果函数内部要修改主调函数中的变量的值就需要传址调用