C
目录
C语法
变量与数值表示
变量范围 有符号
−
2
N
−
1
-2^{N-1}
− 2 N − 1 到
2
N
−
1
2^N-1
2 N − 1 ,无符号0到
2
N
−
1
2^N-1
2 N − 1 。例如char是一个字节,则范围为-128到127,而unsigned char也是一个字节,范围为0到255寄存器类型(register) ,这类变量保存在CPU的一个寄存器中,其访问速度较普通变量快。很少见volatile类型
static变量
在整个程序运行期间都不释放,但作用域不变,也就是说相比全局变量,假如在函数范围内定义一个静态变量,在函数外它是不可使用的,这是它与全局变量不同的地方。静态变量只会初始化一次(编译时),假设多次调用某个定义了静态变量的函数,则该变量也只初始化一次。 静态变量如不初始化,会自动初始化为0.
数制表示
C中无二进制表示方法; 八进制常量必须以数字0开头; 十六进制整常量必须以数字0加X或x开头; aEn或aen 表示
a
1
0
n
a10^n
a 1 0 n 整数后加l表示长整形,加u表示无符号整数,加LL便是long long类型,加f表示浮点型(l、u、f大小写均可);如058L、35u、0xA5LU、356f、2LL
条件编译
#if
常量表达式(注意这里不能使用变量和含有sizeof等在编译时求值的操作符) #elif #else #endif
;#ifdef #else #endif
;#ifndef #else #endif
,注意(a)(b)没有elif选项。也可放在函数中内使用。
位运算
按位异或 a^b ; a|b(或) ; a&b(与) ; ~a(取反) ; >> ,<< (右移及左移)有的系统移入0,有的系统移入1。移入0的称为“逻辑移位”,即简单移位;移入1的称为“算术移位”。例: a的值是八进制数113755 , 用二进制形式表示为1001011111101101
a>>1: 0100101111110110 (逻辑右移时)
a>>1: 1100101111110110 (算术右移时)
在有些系统中,a>>1得八进制数045766,而在另一些系统上可能得到的是145766。Turbo C和其他一些C编译采用的是算术右移,即对有符号数右移时,如果符号位原来为1,左面移入高位的是1。
运算优先级
只有三个优先级是从右至左结合的,它们是单目运算符、条件运算符(?:
)、赋值运算符(=
也是,*=
, /=
等),。其它的都是从左至右结合。a=b=5,then a=5;
单目运算符> 算术运算符 > 关系运算符 > &&
> ||
( !
是单目运算符) > 赋值运算符(=
也是)。 [ ]
和++
的运算优先级都比*
(指针)高 。&
运算优先级比 !=
低 *
的运算优先级只比[ ]
,( )
,点.
,->
,-
,++
,--
低
结构体
结构体可以在函数内部声明,也可以在外部。外部声明的可以为所有函数所使用,函数内部声明的只能在本函数内使用。 初始化结构体数组 struct stu boy[2]={{2010,”John”,19},{2011,”Amy”,20}};
结构体指针 ,ps=&boy; ps->num
与(*ps).num
与boy.num
等价字节对齐 (自身(自身对齐值和指定对齐值中小的那个值)和结构体(其成员中自身对齐值最大的那个值和指定对齐值中小的那个)), 记住是双小就行了
枚举enum
主要应用于需要返回几个状态,但如果写成0,1,2会使得代码不够清晰,这时用枚举,enum STATUS{GOOD,BAD}
,然后当函数返回时便返回GOOD或BAD. 除此之外,当只有某几个状态时,都可以使用enum。 enum中的值是从0开始的,然后下面的逐次加一, 也可以设置任意一个元素的值,后面的元素就在这个元素基础上加1
typedef
自定义变量名:typedef 原类型名 新类型名;
typedef struct pts{ int x; int y; }Point;// Point 不是结构体变量的名称,而是类型名称
typedef struct pts *pPoint
; 然后声明某些指针,可以编写 pPoint pfirst;*typedef int (*func_pointer)(int, int )
; 然后利用func_pointer pfun;
来声明一个这样的函数指针。typedef char Name[10]; then, Name a ; is equivalent to char a[10]
;
C内存分配
分配后要检查是否分配成功(指针是否为空); 需要把返回值强制转换为指针类型;动态内存时方后指针要置为空。 calloc() 与 malloc() 的一个重要区别是:calloc() 在动态分配完内存后,自动初始化该内存空间为零,而 malloc() 不初始化,里边数据是未知的垃圾数据。 void *realloc(void *p, unsigned int size)
用于改变原来通过maloc函数或colloc函数分配的存储空间,即将p指向的存储空间改为size个字节。如果原先的内存大小后面还有足够的空闲空间用来分配,加上原来的空间大小就=newsize 大小的。如果原先的内存大小后面没有足够的空闲空间用来分配,那么从堆中另外找一块newsize大小的内存。并把原来大小内存空间中的内容复制到newsize中。返回新的mem_address指针
数组
数组赋初值 :在给数组赋初值时,如果初值的个数小于数组元素的个数,则剩余的元素自动取值为0,无论几维都一样。在无需赋初值的情况下定义数组时最好这样定义int a[SIZE]={0}; int a[size][SIZE]={0};
但对于字符数组,初值有几个只给相应元素赋初值,其余不做处理 。C语言中数组按行存放的。例:a[4][4]
内存中a[0][3]
后一个元素是a[1][0]
数组名可以作为数组的首地址 ,从而a[i]
等价于*(a+i)
; char a[n]; char *p=&a[0]; 等价于char *p=a
二维数组
二维数组初始化 :int a[2][2]={{1,3},{4,5}}
与int a[2][2]={1,3,4,5}
两者等价对于二维数组a[m][n]
; a
、a[0]
和&a[0][0]
的数值相同,但它们并不是相的东西 访问数组元素的指针表达式,自行百度
字符串
字符串数组 :char s[20]=“I love c”
;使用指针表示字符串 :如果用数组表示字符串,程序代码如下:char s[10]=”Hello”
; 这里对于s数组不能使用s=”12345”
来改变s,只能使用strcpy(s,“12345”)
.但如果使用指针则为 char *ps=”Hello”
, 如果要改变ps则直接使用ps=”1234”
, 但不能使用strcpy
。备忘
gets 碰到空格仍旧读取,scanf("%s",&str)
则遇到空格就停止。getchar(). 字符串常量内存字节数等于字符串中字符数加1,后面加 ‘\0’。 strlen计算的是不包括 ’\0’ 的长度。 将字符串转化为数值(头文件stdlib.h):atof(), atoi(), atol(), atoll()
.
指针
指针基础: &i
表示i
的地址,int *p=&i
或者 int *p ; p=&i
, 然后(*p)
就代表变量i
. int
表示指针所指向变量的类型。 空指针 :为了保证良好的程序设计风格,任何无效的指针都应设为空指针NULL,指针在定义时要将其初始化为NULL常量指针和指针常量
int const* p 或 const int* p
, 不可通过指针修改变量的值,但可以修改指针指向的地址值指针常量 int* const p2
, 不可修改指针的地址值,但可以修改指针指向变量的值 const int* const p3
地址不可改,指向的值也不可通过指针修改 指针运算 :pi += 1
,指针加一的含义是指针向后移动一个元素。实际上这里指针(int类型)所指向的绝对地址变化了4,若指针指向的类型为double,则每次指针加一,其地址数据变化为8. 简而言之,指针加1表示向后移动一个元素,而非表示地址值加1。减法同理。
指向不同类型的指针不能相互赋值,但可以通过强制转换类型将一种指针类型转换为另一种指针类型。long d ;char *p ;p=(char*)&d
;注意只能将&d
而非指针进行类型转换。转换后p指针加1就指向d后一个字节,而非后一个元素,即地址值加1而非加4。 指向数组的指针(数组指针) :int a[5] , (*pa)[5] ; pa=&a (pa=&a[0] is wrong)
, 访问元素时 *p[0]
或(*p)[0]
, p[0]
得到的是地址 ,这里pa++
表示加5个元素, 20个字节 称为行指针 。int *pi=&a[0], then a[3]=0 is equivalent to (*pa)[3]=0 or pi[3]=0 or *(pi+3)=10
,注意pi
与pa
是不同的。指针数组 :*pb[4]
这个数组的每一个成员(加*
)都是指针,当需要通过pb里某个元素的指针来访问它所指向的元素时,使用*pb[1]
, 如果是pb[1]
得到的是一个地址。int main ( )
{
int c[ 4 ] = { 1 , 2 , 3 , 4 } ;
int * a[ 4 ] ;
int ( * b) [ 4 ] ;
b = & c;
for ( int i = 0 ; i< 4 ; i++ )
{
a[ i] = & c[ i] ;
}
printf ( "%d\n" , * ( a[ 1 ] ) ) ;
printf ( "%d\n" , ( * b) [ 2 ] ) ;
system ( "pause" ) ;
return 0 ;
}
行指针和列指针 :int a[3][4] , int (*pb)[4] ; pb=&a[0] ; for(i=0;i<3;i++) (*pb++)[i]=i*i ;
从而a[0][0]=0 , a[1][1]=1 , a[2][2]=4
. 之所以这样乃是pb是包含4元素的数组,pb加1后将指向a[1]数组。pb被称为行指针 。int *pa,pa=&a[0][0]
, 为列指针 。函数指针 :
函数指针即为指向函数的指针变量,可以通过函数指针间接调用函数。int max(int a , int b) ; int (*pf1)(int a , int b) ; pf1=max or pf1=&max;
可将函数指针作为形参,达到调用多个函数的目的。int sum(int, int);
int main(void)
{
int a = 10, b = 5 , result = 0;
int (*pfun)(int, int); pfun = sum; result = pfun(a, b);
printf("result = %d", result);
}
// 还有函数指针数组
int (*pfun[3])(int, int); pfun[0] = sum; pfun[1] = product; pfun[2] = difference;
指针函数
函数的返回类型为指针,常见于各类字符串处理函数。格式:函数类型 *函数名(形参表),例:char * max(char a , char*p), return p(return p1);
调用的时候就是pr=max(a,d);
然后*pr
代表返回值。 指向指针的指针 void p2p(int **pp, int *addr){ **pp = 3; *pp = addr; }
int main()
{
int a = 1; int b = 2;; int *p = &a; int *pb = &b
p2p(&p, pb);
printf("a: %d, b:%d\n", a, b); //结果为 a = 3 , b =2
*p = 4;
printf("a: %d, b:%d\n", a, b); // 结果为 a = 3 , b = 4
return 0;
}
无类型指针(void *) :它是指向无类型数据的指针,也就是说它可以指向任何类型的数据,何类型的指针都可以直接赋值给它(但在C++中这种转换在C++中并不是双向的,在不使用强制转型的前提下,不允许将void*
赋给其他类型的指针,比如:如下代码在C语言中是有效的(但不建议这样写):从void*
隐式转换为double*
, double* pDouble=malloc(nCount*sizeof(double));
但要使其在C++中正确运行,就需要显式地转换:double *pDouble=(double*)malloc(nCount*sizeof(double));)
,无须强制转型。**指针与数组的等价表达 **, 自行百度
C文件
FILE *fp; if((fp=fopen("c:\\zhe.txt","w"))==NULL){ exit(0); } fclose(fp);
打开文件选项
rt或r 只读打开一个文本文件,只允许读数据; wt或w 只写打开或建立一个文本文件,只允许写数据; at或a 追加打开一个文本文件,在文件末尾写数据。 rt+或r+ 读写打开一个文本文件,允许读和写。wt+或w+,at+或at同理; rb,wb,ab,rb+,wb+,ab+适用于二进制文件,与上述类似。 C文件操作相关API ,自行百度
备忘
浮点数与0不可通过等于来比较
时间复杂度对比
O(1)<O(
l
o
g
2
n
log_2n
l o g 2 n )<O(n)<O(
n
l
o
g
2
n
nlog_2n
n l o g 2 n )<O(
n
2
n^2
n 2 )<O(
n
3
n^3
n 3 )<O(
2
n
2^n
2 n )<O(n!)<O(
n
n
n^n
n n )
size_t
size_t 是无符号整形 设计 size_t 就是为了适应多个平台的 。size_t的引入增强了程序在不同平台上的可移植性。size_t是针对系统定制的一种数据类型。为了提高代码的可移植性,就有必要定义这样的数据类型。一般这种类型都会定义到它具体占几位内存等,经测试发现,在32位系统中size_t是4字节的,而在64位系统中,size_t是8字节的,这样利用该类型可以增强程序的可移植性。 打印size_t 类型的值时要小心。这是无符号值,如果选错格式说明符,可能会得到不可靠的结果。推荐的格式说明符是%zu。不过,某些情况下不能用这个说明符, 作为替代,可以考虑%u 或%lu
代码备忘
获得0到limit的随机数
int num; srand(time(NULL)) ; num=rand( )%limit
输入输出重定向到文件
freopen ( "input.txt" , "r" , stdin ) ;
freopen ( "output.txt" , "w" , stdout ) ;
fclose ( stdout ) ; 调试时只有输入这条语句后,结果才会显示内容
如何读取和显示64整形
a) signed 64-bit integer,__int64,scanf("%I64d", &x),printf("%I64d", x);
b) Unsigned 64-bit integer,unsigned __int64,scanf("%I64u", &x); printf("%I64u", x);
c) 也可以写成long long 和unsigned long long 但可能一些编译器不支持,倘若C++的话,那直接cin>>x, cout<<x (有些编译环境不支持)