C进阶5
函数与宏:
#include <stdio.h>
#include <malloc.h>
#define MALLOC(type, x) (type*)malloc(sizeof(type)*x)
#define FREE(p) (free(p), p=NULL)
#define LOG_INT(i) printf("%s = %d\n", #i, i)
#define LOG_CHAR(c) printf("%s = %c\n", #c, c)
#define LOG_FLOAT(f) printf("%s = %f\n", #f, f)
#define LOG_POINTER(p) printf("%s = %p\n", #p, p)
#define LOG_STRING(s) printf("%s = %s\n", #s, s)
#define FOREACH(i, n) while(1) { int i = 0, l = n; for(i=0; i < l; i++)
#define BEGIN {
#define END } break; }
int main()
{
int* pi = MALLOC(int, 5);
char* str = "D.T.Software";
LOG_STRING(str);
LOG_POINTER(pi);
FOREACH(k, 5)
BEGIN
pi[k] = k + 1;
END
FOREACH(n, 5)
BEGIN
int value = pi[n];
LOG_INT(value);
END
FREE(pi);
LOG_POINTER(pi);
return 0;
}
注:
while(1)
{
int k = 0,l = 5;
for (k=0;k<l;k++)
{
pi[k] = k + 1;
}
break;
}
//------------------------------------
递归函数:
函数的无限递归将导致程序栈溢出而崩溃。
#include <stdio.h>
int fac(int n)
{
if (n==1)
{
return 1;
}
else if(n==2)
{
return 1;
}
else
{
return fac(n-1)+fac(n-2);
}
return -1;
}
int main()
{
printf("%d\n", fac(1));
printf("%d\n", fac(2));
printf("%d\n", fac(9));
return 0;
}
汉诺塔问题:
#include <stdio.h>
void han_move(int n, char a, char b, char c)
{
if( n == 1 )
{
printf("%c --> %c\n", a, c);
}
else
{
han_move(n-1, a, c, b);
han_move(1, a, b, c);
han_move(n-1, b, a, c);
}
}
int main()
{
han_move(3, 'A', 'B', 'C');
return 0;
}
//--------------------------------------
当函数参数不应该在函数体内部被修改时,应加上const声明;
如果参数时指针,且仅作为输入函数,则应加上const声明:
void str_copy(char *str_dest,const char *str_src)
函数体规模尽量80行代码以内,参数4个以内。
//----------------------------------
链接脚本:
链接得到elf文件,含有地址信息。
//-------------------------------
arm部分指令集:
LDR R0,[R1] ;将存储器地址为R1的字数据读入寄存器R0。
LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入寄存器R0。
LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入寄存器R0。
LDR R0,[R1,R2] ! ;将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR R0,[R1,#8] ! ;将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1。
LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2写入R1。
LDR R0,[R1,R2,LSL#2]! ;将存储器地址为R1+R2×4的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
LDR R0,[R1],R2,LSL#2 ;将存储器地址为R1的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
LDRB R0,[R1] ;将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零。
LDRB R0,[R1,#8] ;将存储器地址为R1+8的字节数据读入寄存器R0,并将R0的高24位清零。
STR R0,[R1],#8 ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。
STR R0,[R1,#8] ;将R0中的字数据写入以R1+8为地址的存储器中。
STRB R0,[R1] ;将寄存器R0中的字节数据写入以R1为地址的存储器中。
STRB R0,[R1,#8] ;将寄存器R0中的字节数据写入以R1+8为地址的存储器中。
ls -a 显示所有文件,包括隐藏
ls -l 显示文件的详细信息,包括大小时间
ls -al;ls -la;ls -l -a;ls -a -l;
man 1 ls 1表示查询的是linux命令
cd 用来切换目录
cd ./ .代表当前目录;..代表上层目录;
./文件名:执行C文件。
pwd 打印当前目录
mv 源文件的pathname 目标文件的pathname
mv 在目录间移动文件,重命名文件名
touch 创建空文件
touch pathname
cp 复制文件或文件夹
cp 源文件pathname 目标文件pathname
cp -r 用来复制文件夹
cp -f 强制复制
cat 直接在命令行下显示文件内容;也可以用来向文件输入;
rmdir 删除空文件夹,基本没用。
ln
windows中快捷方式和它指向的文件是独立的两个文件;
linux中软连接等同于Windows中快捷方式;
一种叫硬连接,实体链接。
创建软连接文件:ls -s 源文件名 符号连接文件名
举例:ln -s src.c ss.c
l表示符号连接文件;-普通文件;
查找:在命令模式下,输入/xxx,就可以查找到xxx
快速切换行:在命令模式下,输入:num,就可以快速切换到num行
▲符号含义:
..: 代表上一个目录,父目录
-: 代表前一个目录,我刚才从哪一个目录进来的
~: 当前用户的宿主目录,操作系统为当前用户所设计的用来存放文件、工作的默认目录。 如windows中的我的文档目录。
$: 普通用户的命令提示符,#root用户
*: 万能匹配符
使用su 用户名来在不同用户间切换,
行删除: 命令模式下,先将光标移动到要删除的行,然后输入dd,删除3行,3dd。
▲drwxr-xr-x 10个字符,第一个表示文件类型,剩下的9个分成3组,表示文件权限。
rwx中r代表可读w可写x可执行;
▲a=a+b同a+=b;
全局变量没初始化,默认值为0,而局部变量则随机。
▲静态全局变量解决重名问题。
const int *p: p指针指向的一个int型数据,p所指向的是个常量。
int const *p: p指针指向一个int型数据,p所指向的是个常量。
int* const p: p指针指向一个int型数据,p本身是常量,p指向变量。
const int* const *p: p本身是常量,指向也是常量。
注:const在*前面,const作用于p所指向的量,p所指向的是常量。
const在*后面,p本身是个常量,但p指向的不一定是常量。
const指针作用:
char *strcp(char *aa,const char *bb)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
▲C与C++的关系:
c++中所有的变量都可以在需要使用时再定义:
int c = 0;
for(int i = 1;i<=3;i++)
{
for(int j =1;j<=3;j++)
{
c += i * j;
}
}
对比:c语言中的变量都必须在作用域开始的位置定义。
register关键字请求编译器将局部变量存储于寄存器中:
——在c++中可以取得register变量的地址,register只是一个兼容的作用。
C++中不允许定义多个同名的全局变量
c语言中struct定义了一组变量的集合:
typedef struct _tag_student Student;
struct _tag_student
{
const char *name;
int age;
};
C++中,相当于:
struct Student
{
const char *name;
int age;
};
●函数:
int f()与int f(void)有什么区别吗?
答:在c语言中,前者接受任意参数返回值为int;后者不接受参数返回值为int。
在c++中,两者具有相同意义,可接受任意参数。
C语言中真正意义上的常量为枚举,const无法定义真正意义上的常量。
●c语言中的const
const修饰的变量是只读的本质还是变量,其修饰的局部变量在栈上分配空间,
修饰的全局变量在只读存储区分配空间,const只在编译期有用,在运行期无用。
const将具有全局生命周期的变量存储于只读存储区。
▲c++中的const
当碰见const声明时在符号表中放入常量,编译过程中若发现使用常量则直接以符号表中的值替换。
编译过程中若发现下述情况则给对应的常量分配存储空间:
对const常量使用了extern;对const常量使用&操作符。
C++中的const常量类似于宏定义;
C++中的const常量在与宏定义不同:
–const常量是由编译器处理
——编译器对const常量进行类型检查和作用域检查
——宏定义由预处理器处理,单纯的文本替换
//-------------------------------------------------
▲布尔类型
C++中的bool可取的值只有true和false,真1假0.
bool b = 0;
printf("b=%d\n",b); // 0
b++;
printf("b=%d\n",b); // 1
b = b - 3;
printf("b=%d\n",b); // 1
#include <stdio.h>
int main(int argc, char *argv[])
{
bool b = false;
int a = b;
printf("sizeof(b) = %d\n", sizeof(b)); // 1
printf("b = %d, a = %d\n", b, a); //0 0
b = 3;
a = b;
printf("b = %d, a = %d\n", b, a); // 1 1
b = -5;
a = b;
printf("b = %d, a = %d\n", b, a); // 1 1
a = 10;
b = a;
printf("a = %d, b = %d\n", a, b); // 10 1
a = 0;
b = a;
printf("a = %d, b = %d\n", a, b); // 0 0
return 0;
}
//----------------------------------------------------
C语言中的三目运算符返回的是变量值,不能作为左值使用
C++中的三目运算符可直接返回变量本身,既可作为右值也可左值。
三目运算符可能返回的值中如果有一个是常量,不能作为左值:
(a>b?a:b)= 3;成立;(a>b?1:b)=3,不成立;