the C programming language 阅读笔记2
1. 指针
1.1 自增符的使用
++*p;//p指向的内容加一
(*p)++; //p指向的内容加一
*p++;//p本身自增
*++p; //p本身自增
因为诸如*和++这样的一元运算符在表达式求值时按从右到左的顺序和运算分量结合。
1.2 指针运算比数组下标运算快
1.3 数组名
一个数组名即该数组第0个元素的位置,所以赋值语句pa = &a[0]等价于pa = a
1.4 数组下标求值
在求数组元素a[i]的值时,C语言实际上先将其转换成*(a + i)的形式再求值
而对于指针pa而言,pa[i] 等价于 *(pa + i)
1.5 数组名与指向数组首地址的指针的区别
前者非变量,后者为变量
1.6 函数参数传入指针
在函数的定义中,char s[]与char *s是等价的。
当函数参数传入一个较大数组的子数组的指针时,并不会对函数本身造成影响
1.7 指针使用负下标
如果确信某个元素存在,则使用p[ -1]、p[ -2 ]这样的表达式在语法上是合法的。
int b[] = {,,,,,,,,,}; int *a = b + ;
则:a[-3] = 1; a[ -2] = 2;
1.8 alloc与afree的栈式管理
先分配的后释放
调用alloc之前:
allocbuf:
调用alloc之后:
allocbuf:
afree(p)是将空闲单元起始指针指向p位置
1.9 比较运算
在知道指针值意义的情况下,可以对其进行比较运算
int b[] = {,,,,,,,,,}; int *p1 = &b[]; int *p2 = &b[];
则p2 – p1 = 4
1.10 指针相关的有效运算
- 相同类型指针间的赋值运算
- 指针值加或减一个整数值的运算
- 指向相同数组中的元素的指针之间的减或比较运算
- 将指针赋0或指针与0之间的比较运算
1.11 strcpy函数
原书上的函数:
void strcpy( char *s, char *t){ while( *s++ = *t++); }
这里的指针s是临时变量,就算自增也不会改变实参中存储的地址,改变的只是形参指向的地址里的内容,所以用实参可以正确找到首地址,从而正确完成了strcpy函数的功能。
非常感谢@garbageMan的提醒。
1.12 函数参数为二维数组
f( int daytab[2][13])
= f(int daytab[][13])
=f(int (*daytab)[13])
传入一个指针,指针每个元素的内容是一个数组
1.13指向数组的指针和指针数组
int (*daytab)[13] -->指针指向的内容是int[13]的数组
int *daytab[13]à13个指针指向int
指针的实质是根据定义的类型和其中存储的地址来解析内存里的数据
print (Int *s){
s[1] = 5;//即为*(s+1) = 5;
};
*(s+1) = 5;
根据指针所存的地址及所定义的类型,改变其中的数据
int (*daytab)[13]
所定义的类型为int[13]的数组
所以,对该指针解引用得到的是一段13个int长的内存区域的首地址
即:
int a[4][4]; int (*b)[4] = a;
b[2][2] = *(*(b+2)+2) = (*(s+2))[2] != *(s+2)[2]
分析:
*b解引用得到:int[4]
*b的值为这段int[4]的首地址
**b为这段int[4]首地址指向的内容即为b[0][0]的值
1.14 指针数组的初始化
即用指针来初始化数组
1.15 指向函数的指针
1.15.1 一个实例:
支持-n进行数字排序的排序函数
#include <stdio.h>
#include <string.h>
#define MAXLINES 5000 /* max #lines to be sorted */
char *lineptr[MAXLINES]; /* pointers to text lines */
int readlines(char *lineptr[], int nlines);
void writelines(char *lineptr[], int nlines);
void qsort(void *lineptr[], int left, int right,
int (*comp)(void *, void *));
int numcmp(char *, char *);
/* sort input lines */
main(int argc, char *argv[])
{
int nlines; /* number of input lines read */
int numeric = ; /* 1 if numeric sort */
if (argc > && strcmp(argv[], "n")== )
numeric = ;
if ((nlines = readlines(lineptr, MAXLINES)) >= ) {
qsort((void**) lineptr, , nlines1,
(int (*)(void*,void*))(numeric ? numcmp : strcmp));
writelines(lineptr, nlines);
return ;
} else {
printf("input too big to sort\n");
return ;
}
}
/* qsort: sort v[left]...v[right] into increasing order */
void qsort(void *v[], int left, int right,
int (*comp)(void *, void *))
{
int i, last;
void swap(void *v[], int, int);
if (left >= right) /* do nothing if array contains */
return; /* fewer than two elements */
swap(v, left, (left + right)/);
last = left;
for (i = left+; i <= right; i++)
if ((*comp)(v[i], v[left]) < )
swap(v, ++last, i);
swap(v, left, last);
qsort(v, left, last1,comp);
qsort(v, last+, right, comp);
}
1.15.2 指向函数的指针&返回为指针的函数
指向函数的指针:
int (*comp)(void *, void *);
返回为指针的函数:
int *comp(void *, void *);
C在编译时,每个函数都有一个入口地址,该入口地址就是函数指针所指向的地址
有了指向函数的指针变量后,可用该指针变量调用函数
1.15.3 函数指针的定义
1.void (*f)(int x);
调用(*f)(x);
2.typedef int (*fun_ptr)(int,int);
fun_ptr max_func = max;
c = max_func(a,b);
1.15.4 函数指针数组
1.标准定义:
int (*op[2])(int,int);
2.强制类型转换
定义为普通的int型指针数组
在要使用时,强制类型转换为相应的函数指针类型
int *a;
int add(int a, int b);
a = add;
r = ((int (*)(int,int))(a))(numa,numb);
1.16复杂指针的理解
基本形式:
- char **argv; //二维指针
- int (*daytab)[13];//指向一个int[13]数组的指针
- int *daytab[13];//指针数组
- void (*comp)();//函数指针
- void *comp();//返回值为指针的函数
- void (*op[2])();//函数指针数组
char (*(*x())[])()
*x()如上式5,表示返回值为指针的函数
剩余部分表述的就是所返回的指针的类型:
返回的指针类型如上式6,返回值char的函数指针数组
所以,
x是一个函数,该函数的返回值是一个指向类型为char的函数指针数组的指针
char (*(*x[3])())[5]
(*x[3])()如上式6为函数指针数组
其他的部分描述函数指针数组的返回值
所以,x是一个返回值为char[5]的长度为3的函数指针数组
2.内存布局
2.1数组的内存布局
int a[10];
内存是连续分配的相邻区域
int *p = &a;
p = p + 1;
2.2 大端模式 & 小端模式
大端模式:即指数据的高位,保存在内存的低地址中,而数据的低位,保存在内存的高地址中
例:
65534(0x0000FFFE)
小端模式(一字节存储单位):
0x0000 0x0008 0x0010 0x0018
FE FF 00 00
大端模式:
0x0000 0x0008 0x0010 0x0018
00 00 FF FE
3.结构
3.1 结构变量的定义方法
struct {…} x,y,z;
语法上与int x,y,z;相似
3.2 结构变量的定义方法
typedef struct{…} myType;
3.3 结构变量的初始化
struct point maxpt = {320,200};
3.4 对结构体的合法操作
- 拷贝
- 作为一个单元对其赋值
- 通过&取其地址
- 访问结构成员
3.5 结构数组的初始化
struct key{
char *word;
int count;
} keytab[] = {“auto”,,”break”,};
3.6 字节对齐
参加博文《关于C语言中结构体中的结构体成员导致的字节对齐问题》
4.其他
4.1 逗号表达式
逗号运算符,优先级别最低,它将两式连起来,其求解过程先表达式1,后表达式2,整个表达式是表达式2的值
(3+5,6+8) = 14
(a = 3*5,a*4) = 60
4.2 命令行参数
argc 程序执行时命令行中参数的数目
argv 指向字符串数组的指针
4.3 联合
在单独存储区域中管理不同类型的数据
4.4 位字段
struct {
unsigned int is_keyword : ;
unsigned int is_extern : ;
unsigned int is_static : ;
}flags;
分配空间大小为flags分配字段类型最长的倍数,然后一个字节一个字节地存储。在字节内的存储方式未知,根据不同的编译器决定从右往左还是从左往右。GCC是从右往左。
the C programming language 阅读笔记2的更多相关文章
- the C programming language 阅读笔记1
读了一遍著名的<the C programming language>,果然如听说的一样,讲解基础透彻,案例简单典型,确实自己C语言还有很多细节点不是很清楚. 总结一下阅读的收获(部分原书 ...
- C++ Programming language读书笔记
C语言,结构化程序设计.自顶向下.逐步求精及模块化的程序设计方法;使用三种基本控制结构构造程序,任何程序都可由顺序.选择.循环三种基本控制结构构造. 模块结构:"独立功能,单出.入口&quo ...
- The C++ Programming Language 学习笔记 第7章 函数
1.关于内联函数(inline) 借用一下书中的例子. inline int fac(int n) { ) ? :n*fac(n-); } inline描述符给编译器一个提示,要求 ...
- The C++ Programming Language 学习笔记 第6章 表达式和语句
1.关于strcpy函数. 书中说c风格的字符串尽量少用,strcpy这样的函数应该也要少用.这里讲这个函数主要是要通过本章课后练习第十题来讲一下前面提及的要点.巩固一下前几章的知识.写了一段,本来感 ...
- The C++ Programming Language 学习笔记 第5章 指针、数组和结构
1.关于输出指向字符的指针的值. 现在定义,char c='a',char* pc=&c.在C中,输出该值只需要printf("%p\n",pc);而在C++中,如果cou ...
- The C++ Programming Language 学习笔记 第四章 类型和声明
1.关于main 函数中的 return 0 C99标准中,main 函数的返回值类型必须是 int ,这样返回值才能传递给程序的激活者(如操作系统).如果 main 函数的最后没有写 return ...
- 《Multiplayer Game Programming》阅读笔记
在图书馆发现一本<网络多人游戏架构与编程>-- Joshua Glazer, Sanjay Madhav 著.书挺新的,17年出版的,内容很有趣,翻一翻可以学到不少在<计算机网络&g ...
- Programming Ruby 阅读笔记
在Ruby中,通过调用构造函数(constructor)来创建对象 song1=Song.new("Ruby") Ruby对单引号串处理的很少,除了极少的一些例外,键入到字符串字面 ...
- 《The Swift Programming Language》的笔记-第24页
The Swift Programming Language读书笔记学习笔记 第24页 本页主要内容有两个:打印输出和怎样在swift凝视代码 1 怎样打印变量和常量的值? 使用println函数,细 ...
随机推荐
- web Form 表单method="get" method="post" 区别
get和post方法的不同 在B/S应用程序中,前台与后台的数据交互,都是通过HTML中Form表单完成的.Form提供了两种数据传输的方式——get和post.虽然它们都是数据的提交方式,但是在实际 ...
- 蜗牛爱课 - iOS7、8模态半透明弹出框
//源Controller中跳转方法实现 MKDialogController *controller = [[MKDialogController alloc] init]; controller. ...
- UIScrollView基本使用
- (void)viewDidLoad { [super viewDidLoad]; scrollView = [[UIScrollView alloc] initWithFrame:CGRectMa ...
- c#中的数据类型简介(string)
Sting 字符串 引入话题 字符串是一个引用类型,从string数据类型的代码定义中也可以看出它实现了IEnumerable<char>接口和IEnumerable接口,因此字符串可以看 ...
- mysql优化(3) 集群配置
两台服务器 192.168.187.131 192.168.187.132 1.主从配置 131为主 132为从 在131下 vim /etc/my.cnf [mysqld] datadir=/var ...
- 关于jQuery中的ajax的方法介绍
jQuery提供一系列Ajax函数方便我们调用Ajax, 其中最核心也是最复杂的是jQuery.ajax(),所有的其他Ajax函数都是它的一个简化调用.当我们想要完全控制Ajax时可以 ...
- Android 内部启动其他应用,以及打开指定qq聊天界面
在自己应用中打开第三方应用,有好多种方法,这里举例一种: //以打开微信为例,前提需要知道打开应用的包名,一般一个发布版本的应用,包名不会轻易改变的,但是,打开QQ就要注意了,毕竟QQ的发布版本有不下 ...
- Python爬虫:常用浏览器的useragent
1,为什么需要修改UserAgent 在写python网络爬虫程序的时候,经常需要修改UserAgent,有很多原因,罗列几个如下: 不同Agent下看到的内容不一样,比如,京东网站上的手机版网页和p ...
- yum 安装 5.6
http://www.cnblogs.com/XBlack/p/5178758.html
- java应用程序远程登录linux并执行其命令(ssh jar包)
http://www.ganymed.ethz.ch/ssh2/在这个网址下载一个调用ssh和scp命令的jar包. 然后,就可以写程序了.将上面的jar包导入MyEclipse,下面是一个类的实例代 ...