随手记录(之后整理)

关于C语言的指针(书中摘录):

重点1:*p p是什么?指针?更好的叫法应该叫做,地址变量。

    p=(char *)i;

    *p=i&0x0f;

这两句话翻译为汇编:

         MOVECX,i                                             是给ECX寄存器赋值

         MOVBYTE [ECX],(i&0x0f)                  给ECX内存地址赋值

使得存储他们的半导体都不一样,一个在CPU里,一个在内存芯片

如果将这两句话的执行顺序倒过来:

    *p=i&0x0f;

    p=(char *)i;

汇编变为

MOV BYTE [ECX],(i&0x0f)                 

MOV ECX,i                                            

这样在第一个MOV的时候,ECX的值还不确定,是个随机数,导致i&0x0f的结果写入内存不可知的地址中,后果很严重!!!

 

另:char *p;  声明的是p(不要认为是*p)

 

 

重点2:*p 那么p[i]是数组吗?

         写的不好的教科书里,往往会说p[i]是数组p的第i个元素。不算错,可是很敷衍。

         P[i]和*(p+i)意思完全相同。也就是说*p就是p[0]。

更加诡异的是,把p[i]可以写成i[p]。甚至a[2]写成2[a]也是完全没问题的,不会报错,也没有警告。汇编翻译过来完全一样。这总不能说是名叫2的数组的第a个元素吧?

所以p[i]是种省略写法,本质上讲,与数组没关系。


C语言中(“ ”)表示该头文件与源文件位于同一文件夹里。而(< >)则表示该头文件位于编译器所提供的文件夹里。

/

C Primer Plus

    变量在其他文件中定义,则用extern声明就是必须的。

    C99标准,允许在一个代码块中任何位置声明变量。花括号内声明的变量尽在花括号内可见。if语句、for循环,如无括号(可视做默认使用花括号理解)。

有一个外部变量Hocus,如果其他函数没有内部同名的Hocus,则外部变量对其可见(也可声明Hocus为外部变量extern,用来增加可读性)。如果有同名变量Hocus,则同名变量为其内部变量。

存储器类关键字,auto,register,static,extern,typedef(与内存存储无关语法原因归入此类)

malloc 用法 ptd=(double *)malloc(n*sizeof(double));使用动态内存往往导致进程比使用堆栈内存慢。

const,声明中带有关键词const,则不能通过赋值、增量或减量运算来修改该变量的值。(一经定义数值无法修改,可认为只读)
       比如:数码管显示的数组,数组不想被修改,可以使用const定义。

volatile告诉编译器该变量除了可被程序改变以外还可被其他代理改变。(使用它的原因是方便编译器优化)。
    使用地方(编译器每次使用都重新读取数值):
        一般说来,volatile用在如下的几个地方:
    1、中断服务程序中修改的供其它程序检测的变量需要加volatile;
    2、多任务环境下各任务间共享的标志应该加volatile;
    3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义;


restrict通过允许编译器优化某几种代码增强了计算的支持。只可用于指针,表明指针是访问一个数据对象的唯一且初始的方式。


///
判断文件结尾
设计范例#1:
char ch;
FILE *fp
fp=fopen("wacky.txt","r");
ch=getc(fp);
while(ch!=EOF)
{
  putchar(ch);//处理输入
  ch=getc(fp);//获取下一个输入
}

设计范例#2:
char ch;
FILE *fp
fp=fopen("wacky.txt","r");
ch=getc(fp);
while(ch=getc(fp)!=EOF)
{
  putchar(ch);//处理输入
}


#define 一个用法:
#define PSQR(x) printf("The square of "#x" is %d.\n",((x)*(x)))

此处#x称为字符串化。可以把参数名转化为相应的字符串。

使用宏还是函数?空间时间的考量,用宏实现代码会拷贝插入到程序中,执行20次,就有20次拷贝。函数只有一份拷贝。所以节省了空间。内嵌,运行速度更快。
宏的另外一个优点是,它不检查其中的变量类型(无论int或是float都可以使用宏SQARE(x))。

宏函数名,尽量使用大写字母。


#include""    ""表示在当前目录中寻找,然后系统目录
#include<>    <>表示在一个或多个标准系统目录中寻找文件。

其他预处理指令
#undef用来取消定义一个给定的#define.例如:有如下定义:define LIMIT 400 则指令:#undef LIMIT 会取消该定义。

条件编译
#ifdef(#ifndef) #else #endif
            另:可以应用在main函数内。
#if #elif指令
            #if后可以接关系运算符合逻辑运算符(与if类似) #elif及为(else if)


先定义:
struct book{
  char titile[MAXTITL];
  char author[AXAUTL];
  float value;
}
就计算机而言声明:
struct book libry;

是以下声明的简化:
struct book{
  char titile[MAXTITL];
  char author[AXAUTL];
  float value;
} libry;/*在定义之后跟变量名*/

可以进行初始化(用逗号隔开):
struct book libry={
  "The Pirate and the Damsel",
  "Renee Vivotte",
  1.95
}
也可以这样做
struct book libry={.value=1.95,
                   .auther="Renee Vivotte",
                   .tltle="The Pirate and the Damsel"};
.title .author 和.value在book结构中扮演了下标的角色

当要写一个与结构有关的函数。应该用结构指针作为参数,还是用结构作为参数和返回值呢?
指针作为参数优点:C90和C99标准通用,执行快;只需传递一个单个地址。
            缺点:缺少对数据的保护。(用const定义数据可以有效保护)
结构作为参数传递优点是函数处理的是原始数据的副本,比直接处理原始数据安全。编程风格往往更清晰。

    通常程序员为了追求效率而使用结构指针作为函数参数;当需要保护数据、防止意外改变数据时对指针使用const限定词。传递结构值是处理小型结构最常用的方法。

/

联合union 一个能再同一存储空间里(不是同时)存储不同类型数据的数据类型。典型应用是一种表,设计它是用来以某种既没有规律、事先也未知的顺序保存混合类型数据。

枚举类型 (enumerated type)

                 enum声明代表整数常量的符号名称。通过使用关键字enum,可以创建一个新“类型”并指定它可以具有的值。枚举类型的目的是提高程序的可读性。它的语法与结构的语法相同。

                例如:可以这样声明 enum spectrum(red,orange,yellow,green,blue,violet);

                                                     enum spectrum color;

位运算:

打开位

        flags|=MASK;

关闭位

       flags=flags&~MASK;

转置位

       flag^=MASK;

左移<<

     空出的位用0填充

右移>>

      空出的位:unsigned 使用0填充

                          有符号类型结果与机器有关,可能用0填充,或者使用符号填充。


在任何错误的电路上调程序,就是耍流氓。

在任何不稳定的电路上调程序,还不如耍流氓


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值