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函数,细 ... 
随机推荐
- iOS self和super的区别
			self和super的区别 #import <Foundation/Foundation.h> 首先先写两个类 fist和two,two继承fist类 @interface First:N ... 
- 动态获取UIWebView的真正高度
			场景 在 App 中使用UIWebView加载网页, 与原生的 UI 显示在一起,一般情况下,webView 的 内容一页是肯定不够的,换句话说,webView 的高度是不定的,那如果原生的 UI是一 ... 
- global变量
			在函数体内定义的global变量,函数体外可以使用,在函数体外定义的global变量不能在函数体内使用, $global $a; $a=123; function f() { echo $a; //错 ... 
- JSP 最佳实践: 用 jsp:include 控制动态内容
			在新的 JSP 最佳实践系列的前一篇文章中,您了解了如何使用 JSP include 伪指令将诸如页眉.页脚和导航组件之类的静态内容包含到 Web 页面中.和服务器端包含一样,JSP include ... 
- gcc 编译和链接
			1.现在对两个文件生成可执行文件 //thanks.c #include <stdio.h> int main(void) { printf("Hello World\n&quo ... 
- Javascript获取当前时间戳的方法
			定义日期: Date 对象用于处理日期和时间. 可以通过 new 关键词来定义 Date 对象.以下代码定义了名为 myDate 的 Date 对象: var myDate=new Dat ... 
- mudOS配置
			# 本泥巴的名称name : new夕阳再现# 定义用来接受玩家连线的端口#单端口 port number : XXXX#双端口如下:external_port_1 : telnet 10010ext ... 
- PHP获取真实的网络IP
			function get_client_ip() { $ip = $_SERVER['REMOTE_ADDR']; if (isset($_SERVER['HTTP_CLIENT_IP']) & ... 
- PBM文件格式
			PBM是一种单色位图文件,常用于打印机,由于需要下面对PBM文件格式进行分析. 每个文件的开头两个字节(ASCII码)作为文件描述子,可以理解为文件头.具体如下: 头 类型 编码 P1 位图 ASCI ... 
- logstash 操作redis
			在实际应用中,Logstash进程会被氛围两个不同的角色. 运行在应用服务器上的尽量减轻运行压力,只做读取和转发,这个角色叫做shipper 运行在独立的服务器上完成数据解析处理,负责写入到Elast ... 
