Uderstanding and using Pointers 读书笔记
如何阅读指针?
从右向左读。
比如 const int *pci;
虚拟内存和虚拟内存地址是什么?
一个应用程序,在虚拟内存地址里也许是连续的,但是在物理内存里也许是分隔开来的。
虚拟内存和物理内存的映射一般是操作系统主导完成。
程序一般返回的内存地址都是虚拟内存地址。
如何手动 实现 null ?
在许多库里面,NULL 被定义为下面这样的宏
#define NULL ((void *)0)
值为 NULL 的指针不能做什么事情?
不能进行解码,一旦进行解码,就会出现程序终止,因为这个指针实际上并没有含有一个有效的地址。
c 程序编译后,有多少种类型的内存?
Static/Global
当程序运行的时候,这两种类型的变量就一直存在,直至程序终止。
这两个变量的区别是,Global 类型的变量可以被全局访问,而 Static 的变量受函数的范围约束。
Automatic
这种类型的变量在函数里面声明,并且只有当函数被调用的时候才会创建。
他的范围受限于函数,他的生命周期也只有在函数运行的那段时间。
Dynamic
这回总类型的变量,他的内存是从堆里面分配来的,这个变量会一直存在,直到他被声明释放,才会消失。
他的范围受限于指针,或者说,是指针指向的那个内存地址。
总结下
大部分系统下,数据类型的大小是多少?
不同系统下,同一种数据类型的大小可能不同。
%p 的意思是什么?
他的意思是将指针给解析出来,所以你直接传递变量给他去不行的,你要传递地址,也就是指针。
const int 和 int const 的区别
变量类型和 const 关键字的位置顺序并没有什么影响。
下面两个声明都是等同的。
但是 const 在 * 的前后会有影响。
const int *pci;
int const *pci;
const int *p 是怎么回事?
const int *p 是能够使用那些指向 const int 或者 int 类型的指针来赋值的,但是不能改变指针指向的数值,也就是指针解码后的数据是不能够改变的。
int *const p 是啥意思?
这个的意思是, p 这个指针,指向了 int 类型的变量,但是 p 本身已经被声明为了 const 类型,他是不能够改变的。
也就是 p 不能再被赋予其他地址了,但是 p 解码后的数据是能够改变的。
const int * const p 是怎么回事?
这意味着你的指针是 const 的,你的指针指向的类型也是 const 的,所以你无法修改指针的值,也无法修改解码指针后的数据。
const int * const * p 是什么意思?
简单来说,就是一个指针,指向了 「const int * const 类型的指针」。
数组长度是在什么时候确定的?
在程序运行的时候,而不是在编译的时候。
然后,一旦数组被编译创建了,就不能够再改变他的大小了。
动态内存分配函数有几种?
malloc 的形参有需要注意的?
函数原型
void* malloc(size_t);
关于他的形参,有几点需要注意的。
如果你给这个形参传入了负数,那么有的系统会直接报错,有的系统则会返回一个 NULL 值。
如果你给形参赋值 0 ,那么他也许会返回 NULL 值,或者他会返回一个指针指向一个 0 bytes 的内存区域。
如果,你给形参赋值 NULL,则系统会警告,然后返回一个指向 0 bytes 的内存区域的指针。
使用 malloc 的最佳实践是什么?
由于 malloc 也许会返回 NULL ,所以需要在使用 malloc 返回的指针之前,检查一下他返回的值是不是 NULL
int *pi = (int*) malloc(sizeof(int));
if(pi != NULL)
{
// Pointer should be good
}else {
// Bad pointer
}
怎么使用 malloc ?
在编译器的角度来看,= 符号有两种状态,一种是初始化,一种则是赋值,这是不同的两种状态。
错误
static int *pi = malloc(sizeof(int));
正确
static int *pi;
pi = malloc(sizeof(int));
清理内存是怎么做到的?
只要将内存全部设置成二进制的 0 就行了。
calloc 函数的原型是怎样?
calloc 函数会同时分配和清理内存,他的函数原型是这样的。
void *calloc(size_t numElements, size_t elementSize);
什么时候用 calloc ?
当你的内存需要清空的时候,使用 calloc
当某个指向一块内存区域的指针被释放后,这个指针指向什么?
他被释放后,实际上还是指向原本指向的地方,只不过不再能被调用。
dangling pointer 是什么?有什么危害?
你释放了一个指针,然而这个指针没有被赋值为 null ,那么这个指针就是 dangling pointer ,因为他还是指向着之前指向的那块内存区域。
dangling pointer 的危害是:
1、你不能预测这个内存区域是否还会被进行访问。
2、如果这个内存区域不能被访问,而你访问了,则会发声 segment fault
3、隐藏的安全风险
automatic variables 的其他名字是什么?
他也叫做 local variables
被分配到 stack 上。
真正释放指针的最佳实践是什么?
在释放指针后,将指针赋值为 NULL
使用 void 类型有什么需要注意的?
使用 void 类型的形参,可以接受任何类型的变量。
但是如果你没有显示将这个变量强制转换成了 void 类型,那么这个编译器是会提示你警告的。
你只要将这个变量强制转换成了 void 类型就行了。
函数指针和返回指针的函数,别搞混了
函数指针,是指向函数的指针。
而返回指针的函数,只是返回指针。
如何将函数指针简化?
typedef int (*funcptr)(int);
...
funcptr fptr2;
fptr2 = square;
printf("%d squared is %d\n",n, fptr2(n));
上面的 typedef 语句,让 funcptr 这个函数变成了一种类型。
返回一个指针,这个指针指向 int 类型
不要随便对函数指针进行强制类型转换
这种活动一般来说都不能保证每次都能成功。
指针和数组名的区别是什么?
指针可以赋值其他地址,而数组名不行。
如何为函数设定没有固定长度的数组?
使用数组标记法
就是通过一个函数的形参 arr[] 来达到目的的。
void displayArray(int arr[], int size)
{
for (int i = 0; i < size; i++)
{
printf("%d\n", arr[i]);
}
}
int vector[5] = {1, 2, 3, 4, 5};
displayArray(vector, 5);
指针标记法
void displayArray(int* arr, int size)
{
for (int i = 0; i < size; i++)
{
printf("%d\n", arr[i]);
}
}
如何为函数传递二维数组?
你可以使用下面的两种方法来传递二维数组
void display2DArray(int arr[][5], int rows){}
或者是
void display2DArray(int (*arr)[5], int rows){}
需要注意的是,如果写成这样子就没有用了,他表示 arr 数组含有五个元素,每个元素都是指向 int 类型的指针。
void display2DArray(int *arr[5], int rows){}
同理,如果是这样子写就是传递一个三维数组了
void display3DArray(int (*arr)[2][4], int rows)
分配动态数组的方法是什么?
int rows = 2;
int columns = 5;
int **matrix = (int **) malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {
matrix[i] = (int *) malloc(columns * sizeof(int));
}
如何构造参差不齐的数组?
int (*(arr2[])) = {
(int[]) {0, 1, 2, 3},
(int[]) {4, 5},
(int[]) {6, 7, 8}};
构造长的一样的数组
int (*(arr1[])) = {
(int[]) {0, 1, 2},
(int[]) {3, 4, 5},
(int[]) {6, 7, 8}};
为什么不提倡使用参差不齐的数组?
因为你没法记住某个元素的长度究竟是多少,一不小心你就数组越界了。
string 的定义是什么?
string 是一段符号并且以 ASCII 码 NUL 符号结尾的东西。
NUL 意味着 \0
string 一般存储在数组里,在内存里一般分配到堆。
然而,并不是所有的字符数组都是 string,因为他不一定是以 NUL 结尾的。
string 的长度是怎么算的?
一般计算 String 长度的时候,都会忘记 NUL 这个字符,所以如果是分配给某个 string 的长度,一定要记得分配上 NUL 字符的长度。
NUL 和 NULL 有什么区别?
NULL 和 NUL 是不一样的。
NULL 是个特殊的指针,被定义为 ((void*)0)
而 NUL 则是一个 char 类型的字符,并且被定义为 \0
他们两个是不可能互相转换的。
字符变量的长度是多少?
printf("%d\n",sizeof(char));
printf("%d\n",sizeof('A'));
当执行的时候,第一个输出是 1,第二个输出是 4,第二种类型是 character literal,他是 int 类型,这是语言的设计问题。
string 是否可变?
在大部分编译器看来,string 都是常量,但是对于 GCC 编译器来说,却是有办法改变 string 的值。
char *tabHeader = "Sound";
*tabHeader = 'L';
printf("%s\n",tabHeader); // Displays "Lound"
所以最安全的是这样子声明
const char *tabHeader = "Sound";
错误的初始化数组方法
char header2[];
header2 = "Media Player";
左边是数组名是指针,右边是 string,怎么可以这样子赋值
怎么让字符指针初始化为字符串?
char *header = (char*) malloc(strlen("Media Player")+1);
strcpy(header,"Media Player");
使用 malloc 来确定字符串长度的时候,需要注意什么?
一定要记得算上 NUL 这个字符。
不要使用 sizeof 来测量 string 的长度是多少,因为 sizeof 会返回 array 或者 pointer 的大小,而不是 string 的长度。
你应该使用 len 函数来测量。
指针指向结构体的话,解析结构体内元素的方法是什么?
Person *ptrPerson; // Person 是结构体
ptrPerson = (Person*)malloc(sizeof(Person));
ptrPerson->firstName = (char*)malloc(strlen("Emily")+1);
strcpy(ptrPerson->firstName,"Emily");
ptrPerson->age = 23;
另一种解析方法
Person *ptrPerson;
ptrPerson = (Person*)malloc(sizeof(Person));
(*ptrPerson).firstName = (char*)malloc(strlen("Emily")+1);
strcpy((*ptrPerson).firstName,"Emily");
(*ptrPerson).age = 23;
不好的指针申明方式有哪些?
int* ptr1, ptr2;
这个的声明方式, ptr1 才是指针,而 ptr2 是 int 类型的变量。
所以正确的声明方式是
int *ptr1, *ptr2;
错误的内存管理方法
不应该两次 free 一个指针,因为那样子会出错。
DMA 是什么?
Direct Memory Access (DMA)
这是一种 low-level 操作,他用于在内存和其他设备之间传输数据。
这个功能并不是 ANSI C 的功能之一,他是操作系统提供的。
指针别名是怎么回事?
当两个指针指向同一个地址的时候,第二个指针就叫做第一个指针的别名。
如何防止指针别名?
使用 restrict 关键字,在声明这个指针的时候,就使用 restrict 关键字。
他表示这个指针指向的内存是独一无二的,只有他这个指针才能指向,其他指针不能指向这个内存区域。
经常使用 restrict 关键字,有利于提高程序的性能。
Uderstanding and using Pointers 读书笔记的更多相关文章
- 《Essential C++》读书笔记 之 面向过程编程风格
<Essential C++>读书笔记 之 面向过程编程风格 2014-06-18 2.2 调用(invoking)一个函数 2.2.1 Pass by Reference语义 在函数sw ...
- 《More Effective C++》读书笔记(零)Basic 基础条款
这是篇读书笔记,只记录自己的理解和总结,一般情况不对其举例子具体说明,因为那正是书本身做的事情,我的笔记作为梳理和复习之用,划重点.我推荐学C++的人都好好读一遍Effective C++ 系列,真是 ...
- 读书笔记汇总 - SQL必知必会(第4版)
本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...
- 读书笔记--SQL必知必会18--视图
读书笔记--SQL必知必会18--视图 18.1 视图 视图是虚拟的表,只包含使用时动态检索数据的查询. 也就是说作为视图,它不包含任何列和数据,包含的是一个查询. 18.1.1 为什么使用视图 重用 ...
- 《C#本质论》读书笔记(18)多线程处理
.NET Framework 4.0 看(本质论第3版) .NET Framework 4.5 看(本质论第4版) .NET 4.0为多线程引入了两组新API:TPL(Task Parallel Li ...
- C#温故知新:《C#图解教程》读书笔记系列
一.此书到底何方神圣? 本书是广受赞誉C#图解教程的最新版本.作者在本书中创造了一种全新的可视化叙述方式,以图文并茂的形式.朴实简洁的文字,并辅之以大量表格和代码示例,全面.直观地阐述了C#语言的各种 ...
- C#刨根究底:《你必须知道的.NET》读书笔记系列
一.此书到底何方神圣? <你必须知道的.NET>来自于微软MVP—王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心 ...
- Web高级征程:《大型网站技术架构》读书笔记系列
一.此书到底何方神圣? <大型网站技术架构:核心原理与案例分析>通过梳理大型网站技术发展历程,剖析大型网站技术架构模式,深入讲述大型互联网架构设计的核心原理,并通过一组典型网站技术架构设计 ...
- LOMA280保险原理读书笔记
LOMA是国际金融保险管理学院(Life Office Management Association)的英文简称.国际金融保险管理学院是一个保险和金融服务机构的国际组织,它的创建目的是为了促进信息交流 ...
随机推荐
- 关于mysql8启动后又停止(windows10系统),忘记密码以及密码过期等坑解决办法总结!
一 我遇到的问题 1 mysql连接不了,mysql服务启动后又马上关闭 2 忘记密码或者重装服务后提示安装的随机密码过期 一个一个来,先看第一个: 1 出现这个情况很大原因是mysql安装目录有多余 ...
- 《ASP.NET Core 高性能系列》关于.NET Core的配置信息的若干事项
1.配置文件的相关闲话 Core自身对于配置文件不是必须品,但由上文分析可知ASP.NET Core默认采用appsettings.json作为配置文件,关于配置信息的优先等级 命令行>环境变量 ...
- MySQL5.7 中的query_cache_size
摘自:http://jackyrong.iteye.com/blog/2173523 1 原理 MySQL查询缓存保存查询返回的完整结果.当查询命中该缓存,会立刻返回结果,跳过了解析,优化和执行 ...
- DotNetty发送请求的最佳实践
长链接发送request/response时, 绝大部分包都是小包, 而每个小包都要消耗一个IP包, 成本大约是20-30us, 普通千兆网卡的pps大约是60Wpps, 所以想要提高长链接密集IO的 ...
- winsocket入门学习
参考资料:http://c.biancheng.net/cpp/socket/ http://www.winsocketdotnetworkprogramming.com/ socket 是" ...
- Java中正确终止线程的方法
Thread类中有一个已经废弃的 stop() 方法,它可以终止线程,但由于它不管三七二十一,直接终止线程,所以被废弃了.比如,当线程被停止后还需要进行一些善后操作(如,关闭外部资源),使用这个方法就 ...
- Linux/UNIX编程:获取指定用户所有正在运行的进程ID和进程名
先用系统函数 `getpwnam` 获得指定用户名的 UID,然后遍历 /proc/ 中所有 PID 目录,如果 /proc/PID/status 中的 UID 是输入用户名对应的 UID 则输出该 ...
- HDU_1394_线段树
http://acm.hdu.edu.cn/showproblem.php?pid=1394 线段树入门题,每次读入一个数,就寻找在树中比它大的值的个数,然后更新树,把个数相加就是逆序数,每移动一个数 ...
- EMC NW NMM to restore MS AG database
Following last article, how to restore MS AG database , that is in the following: You see ? Cheer u ...
- [信息安全] 05 X.509 公钥证书的格式标准
X.509是# 公钥证书的格式标准, 广泛用于TLS/SSL安全通信或者其他需要认证的环境中.X.509证书可以由# CA颁发,也可以自签名产生. 1 Overview {#1-overview} X ...