C指针基础知识
指针的声明
C语言声明格式:"类型 变量名;"
- 基本类型:
int hoge; - 指针类型:
int *pointer;
区别在于:
| 声明 | 含义 |
|---|---|
| int hoge; | 声明整数类型的变量 hoge |
| int *pointer; | 声明 "指向int的指针"类型的变量 pointer |
关于int *pointer; 其:
| 指针类型 | 指向int的指针 |
| 指针类型的变量 | pointer |
| 指针类型的值 | 内存的地址 |

C语言的数据类型参考:C 数据类型-菜鸟教程
- 代码示例 pointer.c
指针运算
对指针进行加 N 运算, 地址的值会增加当前指针所指向数据类型的长度 ✖ N
- 代码示例 pointer-calc.c
空指针
确保没有指向任何一个实际的对象或者函数的指针.通常使用宏定义NULL来表示空指针常量值.
- 代码示例 null_pointer.c
指针与数组
表达式中,数组可以解读成 "指向它的初始元素的指针".(有例外)
p[i] 是 *(p+i) 的简便写法.
C的数组从0开始原因:
- 解决生活中"差1错误"问题
- 在支持指针的语言中,标号被视作是偏移量,因此从0开始更符合逻辑
当今的操作系统都会给应用程序的每一个进程分配独立的 "虚拟地址空间".
操作系统负责将物理内存分配给虚拟地址空间,同时还会对每一个内存区域设定"只读"或者"可读"属性.
- 代码示例 vmtest.c
变量储存地址
| 储存期 | 含义 | 寿命 |
|---|---|---|
| 静态变量 | 全局变量,文件内的static变量,指定static的局部变量都持有静态储存周期 | 从程序运行时开始,到程序关闭时结束 |
| 自动变量 | 没有指定static的局部变量持有自动储存期 | 到声明该变量的语句块执行结束为止 |
| malloc() | 变量通过malloc()分配的领域 | 到free()释放为止 |
- 代码示例 print_address.c
自动变量(栈)
自动变量重复使用内存区域,因此自动变量的地址不是一定的.
- 代码示例 auto.c
大部分CPU中已经嵌入栈的功能,C语言通常直接使用.
C语言中,通常将自动变量1保存在栈中.
assert(条件表达式):若表达式为真,assert()不执行任何动作,否则在标准错误 stderr 上显示错误消息,并中止程序执行.
动态内存分配
malloc():
- 声明:
void *malloc(size_t size) - 功能:分配所需的内存空间,并返回一个指向它的指针.
- 在标准C库中,提供了
malloc/free函数分配释放内存,这两个函数底层是由brk,mmap,munmap这些系统调用实现的,但他们不是系统调用,是标准库函数.
可能调用 free() 后,对应的内存区域不会立即返还给操作系统,因为可能有2个指针(A与B)在引用当前区域的情况出现,使用指针A引用的区域后仓促调用 free() ,指针B引用的内存区域也不会立即破坏,暂时保留以前的值,直到某个地方执行 malloc() ,随着当前内存区域被重新分配,内容才开始被破坏.
- 代码示例 free.c
碎片化 : 内存被零零散散分割,出现较多无法利用的细碎空块.
使用malloc()的内存管理过程,可能引发碎片化
realloc()
- 声明:
void *realloc(void *ptr, size_t size) - 功能: 尝试重新调整之前调用
malloc或calloc所分配的ptr所指向的内存块的大小,即扩展内存区域. 如果通过ptr传递的区域后面有足够大小的空闲空间,则直接实施内存区域扩展. 若没有足够多的区域,则分配其他新空间,然后将内容复制过去. realloc同样可能引发碎片化,但相比malloc较为缓和,但要是用在扩展较大的内存区域,除了复制耗时,也会造成堆中大量的空间过分活跃,此时应该积极使用链表.- 代码示例 realloc.c
布局内存对齐
根据硬件(CPU)的特征,对于不同数据类型的可配置地址受到一定的限制.
为了提高CPU的效率,编译器会适当地进行 边界调整(布局对齐) ,在结构体中插入合适的填充物(也就是再添加适当大小的储存空间). 但即便使用手工进行布局对其,也不能提高可移植性.
- 代码示例 alignment.c
字节序
字节序,即字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前.
字节排序分为大端字节序和小端字节序. 说明见代码
- 代码示例 byteorder.c
- 无论是整数还是浮点数,内存上的表现形式都随环境(CPU)的不同而不同.

C语言的声明
要用英语来解读 C 的声明.
- 首先着眼于标识符(变量名或者函数名).
- 从距离标识符最近的地方开始,依照优先顺序解释派生类型(指针.数组和函数).优先顺序说明:
- 用于整理声明内容的括弧
- 用于表示数组的 [],用于表示函数的 ()
- 用于表示指针的 *
- 解释完派生类型,使用"of","to","returning" 等将他们连接起来.
- 最后,追加数据类型修饰符(在最左边,int double等).
| C语言 | 英语表达 | 中文表达 |
|---|---|---|
| int hoge; | hoge is int | hoge 是 int |
| int hoge[10]; | hoge is array(元素个数10)of int | hoge 是 int 的数组(元素个数10) |
| int hoge[10][3]; | hoge is array(元素个数10) of array(元素个数3)of int | hoge 是 int 数组(元素个数3)的数组(元素个数10) |
| int *hoge[10]; | hoge is array(元素个数10) of pointer to int | hoge 是指向 int 的指针的数组(元素个数10) |
| int (*hoge)[3]; | hoge is pointer to array(元素个数3) of int | hoge 是指向 int 的数组(元素个数3)的指针 |
| int func(int a); | func is function(参数为int a) returning int | func 是返回 int 的函数(参数为int a) |
| int (*func_p)(int a); | func_p is pointer to function(参数为int a) returning int | func_p是指向返回 int 的函数(参数为int a)的指针 |
C语言的表达式
基本表达式:
- 标识符(变量名,函数名)
- 常量(包括整数常量和浮点数常量)
- 字符串常量(使用 " " 括起来的字符串)
- 使用 () 括起来的表达式
左值
作为变量,它有作为 "自身的值" 和作为 "自身内存区域" 两种情况, 例如 hoge = 10; 和 *hoge_p = &hoge; *hoge_p = 10; .像这样表达式代表某处的内存区域的时候,称当前的表达式为左值(lvalue); 相对的,当表达式代表值的时候,称当前表达式为右值 .
数组和指针相关的运算符
| 运算符 | 作用 |
|---|---|
* |
单目运算符,称为解引用.将指针作为操作数,返回指针所指向的对象或者函数. 只要不是返回函数,运算符*的结果都是左值 |
& |
单目运算符,称为地址运算符.将一个左值作为操作数,返回指向该左值的指针.对左值的类型加上一个指针,就是&运算符的返回类型 |
-> |
箭头运算符,通过指针访问结构体的成员的时候,用它引用某成员 |
const
const是在ANSI C中追加的修饰符,它将类型修饰为"只读"
可以定义const常量,但const不一定代表常量
假如有一个结构体:
struct Books{
char *title;
int price;
char isbn[32];
};
void regist_book(struct Books const *book_data)
因为使用了const所以book_data所指向的对象是禁止改写的,但book_data->title所指向的内容是可以被改写的.
这种情况是因为由于const而成"只读"对象是 "book_data所指向的对象自身" ,而不包括 "book_data所指向的对象再向前追溯到的对象" 即结构体内的title所指向的对象.解决办法为char const *title
指针常量与指针变量
数组指针和指针数组
详见:数组指针与指针数组
C指针基础知识的更多相关文章
- Boost智能指针-基础知识
简单介绍 内存管理一直是 C++ 一个比較繁琐的问题,而智能指针却能够非常好的解决问题,在初始化时就已经预定了删除.排解了后顾之忧.1998年修订的第一版C++标准仅仅提供了一种智能指针:std::a ...
- C语言指针入门知识
C语言指针往往是C语言学习过程中最困难的地方, 最近重新理解了一下C语言的指针知识, 在此整理一下, 如果有错误请留言指正. 对于刚入门的人来说, 指针涉及方方面面, 从简单的数组到结构体, 都会用到 ...
- 曹工说Redis源码(2)-- redis server 启动过程解析及简单c语言基础知识补充
文章导航 Redis源码系列的初衷,是帮助我们更好地理解Redis,更懂Redis,而怎么才能懂,光看是不够的,建议跟着下面的这一篇,把环境搭建起来,后续可以自己阅读源码,或者跟着我这边一起阅读.由于 ...
- C++指针和结构体基础知识
学习C++首先要回忆起C语言当中的指针和结构体知识,本文作者将通过一段代码来总结指针和结构体基础知识:指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址.就像其他变量或常量一样,您必须在使 ...
- LLDB基础知识
LLDB基础知识 LLDB控制台 Xcode中内嵌了LLDB控制台,在Xcode中代码的下方,我们可以看到LLDB控制台. LLDB控制台平时会输出一些log信息.如果我们想输入命令调试,必须让程序进 ...
- Oracle数据库基础知识
oracle数据库plsql developer 目录(?)[-] 一 SQL基础知识 创建删除数据库 创建删除修改表 添加修改删除列 oracle cascade用法 添加删除约束主键外 ...
- C++ 顺序容器基础知识总结
0.前言 本文简单地总结了STL的顺序容器的知识点.文中并不涉及具体的实现技巧,对于细节的东西也没有提及.一来不同的标准库有着不同的实现,二来关于具体实现<STL源码剖析>已经展示得全面细 ...
- C#基础知识记录一
C#基础知识记录一 static void Main(string[] args) { #region 合并运算符的使用(合并运算符??) 更多运算符请参考:https://msdn.microsof ...
- jquery基础知识汇总
jquery基础知识汇总 一.简介 定义 jQuery创始人是美国John Resig,是优秀的Javascript框架: jQuery是一个轻量级.快速简洁的javaScript库.源码戳这 jQu ...
随机推荐
- CStatic设置位图
CStatic 用于显示位图 如果要显示图标,则必须要设置窗口属性为 SS_BITMAP 和 SS_CENTERIMAGE,实例代码如下: //获得指向静态控件的指针 CStatic *pStatic ...
- 简述cookie ,localStrage,sessionStorage的区别?
1.cookie: 是一个回话跟踪技术,信息存储在用户硬盘,可以做全局变量. 什么是会话:用户进入网站,开始浏览到结束的这样的一个过程,称为一次会话. 会话跟踪技术:浏览器和服务器之间进行多次请求数据 ...
- uvalive 3231
3231 - Fair ShareAsia - Seoul - 2004/2005You are given N processors and M jobs to be processed. Two ...
- (C/C++学习)10.C++文件流
说明:C++中的文件流分为三种:文件输入流.文件输出流.文件输入/输出流,其对应的类分别为 ifstream.ofstream 和 fstream .由这三个类创建类对象,完成对文件的操作.其中文件的 ...
- iptables简单了解
简介 Iptables是unix/linux自带的一款优秀且开源的基于包过滤的防火墙工具. 怎么用 可以用来做主机防火墙. 可以做局域网共享上网. 可以做ip及端口映射. Iptables工作流程 i ...
- STM32窗口看门狗和独立看门狗的区别,看门狗介绍及代码演示
一.介绍: STM32看门狗分为独立看门狗和窗口看门狗两种,其两者使用调条件如下所示, IWDG和WWDG两者特点如下图所示: 独立看门狗的手册资料: 窗口看门狗的手册资料: ...
- 关于单片机编程里面调用sprintf死机的解决方法及原因分析
好久之前的做的笔记,这里贴出. char String[100];//直接用数组代替指针即可解决 下面代代码下载至单片机中,发现会出现单片机死机问题 #include "stdio.h&qu ...
- 2.2 为什么要使用Shell脚本
使用脚本编程语言的好处是,它们多半运行在比编译型语言还高的层级,能够轻易处理文件与目录之类的对象.缺点是:它们的效率通常不如编译型语言.不过权衡之下,通常使用脚本编程还是值得的:花一个小时写成 ...
- List多字段排序,orderBy,ThenBy
List排序问题,orderBy,ThenBy 1.List中一个字段排序 前几天做的项目中,获取的List<T>需要用某个字段来进行排序,困扰了很久.用OrderBy解决了.具体是这样的 ...
- SVN学习总结(3)——分支合并
首先在主干trunck上,创建分支branch1.0.0,如下图: 从主干切换到branch1.0.0,在branch1.0.0中添加test.java文件, 分支与主干的合并,首先应将主干trunc ...