德良 - 云代码空间
—— Coding是一种生活!
C/C++部分
1.编译
gcc -c xx.c形成一个xx.o文件
2.连接
gcc xx.o形成a.out可执行文件(gcc xx.o -oxxx制定生成xxx.o文件)
注释:include头文件 ls /usr/include;
vi 中显示行数设置 set nu;
C语言注释/* */;C++下的注释//;
续行符"\":如#include \
<stdio.h>,即下一行和上一行为一个语句;
C语言结尾一般留出一个空行;
'0'--'9'ASCLL码:48--57;
数字-->字符:+'0';字符-->数字:-'0';
3.输出格式
%i/%d:int
%hd/%ld:short int/long int
%u:unsigned int
%f/%lf:float/double
%g:float/double去掉了尾随的0
%x/%o:十六进制/八进制
%p:地址
%c:字符
%s:字符串
4.变量
变量的类型:字母、数字、下划线(数字不能放在前面)
如:int a;正确
int 5a;错误
5.类型转换
强制类型转换:int n=(int)3.14159;(类型转换,只是值的转换,变量类型不会改变)
注释:如何看汇编gcc -S xx.c/cpp;
定义宏预处理#define name "Jack"(在程序中用name替换Jack),查看宏:gcc -E xx.c/cpp(注意:宏的后面没有";"分号);
定义一个常量,必须一并初始化,否则在后面就不能给之赋值,因为常量不能改变它的值,如 const int p=2;
6.运算符
位运算符:& 与 1&1->1
| 或 1|0->1
^异或 1^1->0 1^0->1(作用,可以把某个或几个反转)
注释:逗号运算符做运算,以第二个作为实际值,如:
printf("%d\n",(a=123,b=456));输出的值为456;
运算符右结合顺序:如printf("%d %d %d\n",i++,i++,i++);
输出从右向左,比如i初始值为0,则输出结果2,1,0;
7.输入输出
------清除输入缓冲区剩余字符:scanf("%*[^\n]%*c");
8.循环
对于continue和break,用于循环之中,continue是跳过循环中continue后面的语句,继续执行循环中前面的语句;break是直接跳出循环体;
9.枚举
#include<stdio.h>
enum bool{true,false};
//大括号里面的是枚举常量(字面量),它的值默认第一个是0,后面的依次加1
//比如这里true=0,false=1;可以指定值,比如true=1,false=0;
//枚举里面的字面量必须是整型
enum mode{};
void main()
{
printf("%d\n",true);
}
10.类型起别名(声明一个新的类型名)
typedef int T;
T a;
T b;//相当于int b;
注意:typedef只是对已存在的类型增加一个类型名,而并没有创造一个新的类型;
===================================
<给什么起别名,typedef给int起别名T>
===================================
11.数组
数组名表示第一个元素的地址;
数组名本身不是一个变量,不占有存储空间;
字符数组:
例1.
#include<stdio.h>
void main()
{
char m[4]={'a','b','c','d'};//m是个字符数组,但不是字符串(字符串有结尾标志"\0")
}
例2.
字符数组初始化(只可以初始化,不可以赋值):
char a[100]="hello world!";
不能a="hello world1",但可以strcpy(a,"hello world!");
#include<stdio.h>
#include<string.h>
void main()
{
char a[100]="Hello world!";
puts(a);
strcpy(a,"Good afternoon ");
puts(a);
strcat(a,"friends!");
puts(a);
printf("%s\n",strchr(a,'f'));//在a中查找f,并输出其后的字符串
printf("%s\n",strrchr(a,'f'));//从右向左查找f,并输出从右向左查找的字符串
}
注释:sizeof()只关心类型,不关心内容;strlen()测试字符串长度;
int a[10];n那么a的类型是int[5];
字符串的输出,找到他的地址(第一个元素的地址),然后输出,直到'\0'结束;
11.结构
char a[1][2]={{"",""},{"",""}};
对齐和补齐问题(存放的起始地址是自身的倍数开始):
struct Person{
char name;//1
int age;//跳过3个字节,即从第四个地址开始
int id;//4
char sex;//1,但是补齐3个,总共占4个字节
}p;
所以sizeof(p)=16;(一般是以int即4为单位);
struct Goods{
char name[17];//从0开始到17,共占17字节
char special;//17是1的倍数,故占18这个地址,占1个字节
short sale;//从18开始,18是2的倍数,占两个字节
double price;//从20开始,占8个字节
int num;//从28开始,28是4的倍数,故占4个字节
}g;
所以sizeof(g)=32;
12.联合(union)
联合即共用体,占用同一块内存,对一个成员进行操作,则会影响其他成员;
定义和使用类似结构体;
13.函数
防止回车换行符影响读入操作,那么在scanf前加一个空格符,例如:
scanf(" %c",&name);
注释:如何清除缓冲区
void clear()
{
scanf("%*[^\n]");
scanf("%*c");
}
==============================
如何将数字0--9转化为汉字:
char nem[10][5]={"零","一","二","三","四","五","六","七","八","九"};
printf("%s",num[c-'0']);
14.变量修饰
对全局变量/函数加static,表示只能在本文件中使用。
全局变量和静态局部变量自动初始化为零;
将一个变量申明放在寄存器(register)中,就不要去取地址;
C中函数参数和类型是空的,表示参数不定,即也可以任意传参数;
如果加了void,则表示不接受任何参数,如void fun(void),即不传;
注释:如何让一个数加倍,左移即可,如a=11,a<<=1,则a=22;
栈用来保存函数的返回地址;
15.可变长参数列表
例:不定长参数求最大值:
#include<stdio.h>
#include<stdarg.h>
int max(int cnt,...)//可变长参数列表
{
va_list v;//v保存可变长参数表,va_list是一个类型
va_start(v,cnt);//开始一个可变长形参列表,从cnt开始,用v保存cnt之后参数
int i;
int maxvalue=va_arg(v,int);//取元素,第二个参数是要取参数的类型
for(i=1;i<cnt;i++)
{
int data=va_arg(v,int);
if(data>maxvalue)
maxvalue=data;
}
va_end(v);//释放可变长参数表v
return maxvalue;
}
void main()
{
printf("%d\n",max(2,36,56));
}
16.宏(macro)
例1:
#include<stdio.h>
#define H "Hello\n"
#ifndef H
#define H "你好!\n"
#else
#define __H H
#undef H
#define H "**\n"
#endif
void man()
{
H;
}
例2:
#ifndef VX
#define VX 1
int x=2;
#endif
例3:(宏可以带参数--宏函数)
#include<stdio.h>
#define SWAP(T,x,y) {T t=x;x=y;y=t;}
void main()
{
int a=9,b=10;
SWAP(int,a,b);
}
例4:(带参数的宏总要用括号括起来)
#define APEA(r) PI*(r)*(r)
c中内置的宏:
__FILE__ "predef.c"
__LINE__ 表示当前的行
__DATE__ 表示当前日期
__TIME__ 表示当前时间
17.指针
1.指针,其实是两个变量(地址和保存地址的变量);
int *p=NULL;p是一个指针,指向int型的指针;
2.野指针:
int *p;
printf("p=%p\n",p);//这里p就是野指针
(尽量避免野指针,初始化int *p=NULL;)
注释:函数中返回局部变量的地址
例:char *fun()
{
char a='&';
return &a;//不要返回普通局部变量的地址;
}
int main()
{
char *p=NULL:
p=fun();//这里函数fun()返回局部变量之后,
局部变量出了函数之后会消失,此时返回的指针已经悬空,
即指向一个可能已经释放的地方;
}
3.定义指针变量:
int *p=NULL,q=NULL;//此处并不能成功定义q;
int *p=NULL,*q=NULL;//正确
4.内存中交换地址并不能交换元素值(相当于左右分别站了一个男的和一个女的,
用左右手指分别指向他们,现在改变手指指向
<类似改变指针变量指向>,但他们人本身并没有改变<即值没有改变>);
5.C中是值传递;
6.指针变量永远占4字节:
如:char *p="Hello";sizeof(p)=4;
7.形参里面的数组名实际是指针:
#include<stdio.h>
print(int m[],int n)
{
printf("sizeof(m)=%d\n",sizeof(m));
}
void main()
{
int a[3]={1,2,3};
print(a,3);
}
结果是:4;因为print(int m[],int n),其实就是print(int *m,int n);
8.const对指针的使用(见附录:const对指针操作实例);
9.区分:
int *a[5]//a是一个数组,里面有5个元素,每个元素是int*-----a不是指针,只是一个数组名而已,指针数组;
int *a(double)//a是一个函数,有一个形参类型是double,返回int*;
int(*a)[5]//a是一个指针,指向一个含有5个元素的int型的数组------即a指向数组的指针;
10.函数指针(指向函数的指针):
如:int(*p)(double)
================================================
注释:问一个类型,只要去掉元素名,剩余的就是类型;
三目运算符a>b?a:b,':'前后类型要相同;
================================================
11.结构体变量做函数参数时,要传递的是地址;
12.堆(heap):
#include<stdio.h>
#include<stdlib.h>
int main()
{
double *p=(double*)malloc(sizeof(double));
int *a=calloc(5,sizeof(int));
printf("p=%p,a=%p\n",p,a);
*p=12.23;
int i;
for(i=0;i<5;i++)
{
a[i]=i+10;
}
free(p);
a=realloc(a,10);//对原来a空间重新分配10空间
free(a);
}
12.1:对于事先不知道需要多大空间时,用到malloc,即动态内存,不受作用范围限制;
12.2:有申请就要有释放;
C++
1.C++中成员地址和函数地址,都为true。
2.引用:
3.C++不提倡用宏。
4.C++类型转换:
static_cast数值类型之间,有一方是void*的指针类型之间
例如:int n=static_cast<int>(46.25);
const_cast用于临时去掉const、volatile限制
例如:int n=10;
const int k=n; const_cast<int&>(k)=23;
reinterpret_cast 任意两种指针类型之间,指针于数值类型之间
例如:float f=123.12;
p=reinterpret_cast<int*>(&f);
dynamic_cast
5.关键字:~compl ^xor !not |bitor ||or &bitand
&&and !=not_eq &=and_eq |=or_eq ^=xor_eq
new:new 类型
delete:
new和delete:
#include<iostream>
#include<cstdlib>
using namespace std;//new 类型==>(类型*)malloc(sizeof(类型))
int main()
{
int* p=static_cast<int*>(malloc(sizeof(int)));
int* q=new int;//不保证是零
int* r=new int (888);//用888初始化*r
int n=10;
int* a=new int[n];//不保证是零
delete r;r=NULL;
delete q;q=NULL;
delete []a;a=NULL;//释放一片空间
free(p);//malloc申请的要用free释放
return 0;
}
6.函数地址和成员地址输出都为true。cout<<&main<<endl;
7.函数在代码区,数据在数据区,sizeof时,函数不会有大小。
8.char next()const{return a[cur++];}//此处的const表示不会修改当前对象
9.求最大公约数:
int maxcd(int a,int b){
if(a==0) return b;
return maxcd(b%a,a);
}
10.C++类中,不管什么变量,至少占一个字节(内存分配,是以字节为单位);
new一个数组的时候会额外分配4个字节,来保存数组中元素个数,这样delete时才知 道释放多少;x=new A[3];sizeof(x)=7,即3+4;
11.指针只能保存地址,如果要保存字符串,用数组 如:char a[100];
12.继承:子类先调用父类的构造函数;
虚基类构造函数参数由底层子类直接传递
父类构造顺序按照继承顺序
继承,避免代码重写,子类对象一定是父类对象;
13.多态:只有通过指针调用虚函数是,才会实现多态;
一个类,如果它的实现交给子类来实现,那么就写成虚函数;
多态:继承、虚函数、指针或引用;
构造、析构函数中没有多态(子类先调用父类的构造函数,子类的);
14.应用(&)是C++特有的;
1...静态成员函数,友元函数,虚基类;
一个函数操作对象不依赖当前对象(整体行为),定义为静态成员函数,静态成员变量在类外初始化,因为它属于整个类;
附录:
1:const对指针操作实例
#include<stdio.h>
#include<string.h>
void main()
{
char a[20]={'h','e','\0','w','o'};
"csd1007";
puts(a);//he
puts("csd1007");//csd1007
char *p=a;
printf("%c\n",*p);//h
//printf("%s\n",p);//he
*p='w';
puts(a);//we
p="csd1007";//编译器可能会有警告
printf("%c\n",*p);//c
//*p='w';//断错误
const char *q=NULL;//等价char const *q=NULL;
q="csd1007";//只是把字符串第一个地址赋给指针q
//*q='w';//q只读,不能赋值
p=a;
strcpy(a,"NB");
puts(a);//NB
q=a+3;
puts(q);//wo
char *const r=a;//表示指针r是一个常量
*r='A';
puts(a);//AB
//const char *m表示对对所指的目标只能进行读操作
//char *const n表示此指针只能进行读操作
}
2:程序4--利用二级指针返回字符串
#include<stdio.h>
int fun(const char *cstr,const char **q)
{
int r=0;
while(isdigit(*cstr))
{
r=r*10+*cstr-'0';
cstr++;
}
*q=cstr;
return r;
}
void main()
{
const char *str=NULL;
int n=fun("123abc",&str);
printf("%d,%s\n",n,str);
}
结果:123,abc
3:动态数组
动态数组:
#include<iostream>
using namespace std;
char mem[10000];
int pos;
class A{
public:
A(){cout<<"A()"<<endl;}
~A(){cout<<"~A()"<<endl;}
static void* operator new(size_t bytes)
{
cout<<"new A"<<bytes<<endl;
int alloc=pos;
pos+=bytes;
return mem+alloc;
}
void operator delete(void *p){cout<<"delete A"<<endl;}
static void* operator new[](size_t bytes)
{
cout<<"new A[]"<<bytes<<endl;
int alloc=pos;
pos+=bytes;
return mem+alloc;
}
void operator delete[](void *p){cout<<"delete A[]"<<endl;}
};
int main()
{
A* x=new A;//1、分配空间;2、执行构造函数
delete x;//1、执行析构函数;2、释放空间
x=new A[3];
delete[] x;
}