数据类型:(32位机)
char short int(4字节,32位) long(4)
double(8字节) float(4)
构造类型:
数组 struct uinon enum
指针:
void:
位运算:
位与 位或 位取反 位异或 逻辑取反
& | ~ ^ !
左移 <<
右移 >>
读-改-写
特定位清零用 &
特定位置1用 |
特定位取反 ^
位运算与宏定义
#define SET_NTH_BIT(x, n) (x | ((1U)<<(n-1)));
#define CLEAR_NTH_BIT(x, n) (x & ~((1U)<<(n-1)));
指针:
* &
const int* p;//指向整形常量 的指针,它指向的值不能修改
int const *p;//指向整形常量 的指针,它指向的值不能修改
int* const p;//指向整形的常量指针 ,它不能再指向别的变量,但指向(变量)的值可以修改
const int* const p; //指向整形常量 的常量指针 。它既不能再指向别的常量,指向的值也不能修改
初始化的全局变量和静态的变量放在.data段
未初始化化的全局变量和未初始化的静态变量放在.bss
int a[10]
a a[0] &a &a[0]
a 左值 sizeof(a) 4*10
a做右值等同于 &a[0]
&a 不能左值,右值 数组的首地址
&a[0]
数组名[下标])和指针 *指针+偏移量
int* p; int a[5]; p = a; 匹配
int* p; int a[5]; p = &a; 类型不匹配,&a是整个数组指针,是一个数组指针类型,不是int指针类型
&a、a、&a[0] a和&a[0]是元素指针,int 类型; &a 是数组指针,是int()[5]
指针变量+1,是加 1*sizeof(指针类型)
char str[] = ”hello”; sizeof(str) 6 sizeof(str[0]) 1 strlen(str) 5
char *p=str; sizeof(p) 4 sizeof(*p) 1 strlen(p) 5
strlen接收的参数必须是一个字符串(字符串的特征是以’\0’结尾)
输入型参数和输出型参数:
函数名是一个符号,表示整个函数代码段的首地址
参数多的时候打包成结构体,传结构体变量的指针
函数传参中使用const指针
(1)const一般用在函数参数列表中,用法是const int *p;(意义是指针变量p本身可变的,而p所指向的变量是不可变的)。
(2)const用来修饰指针做函数传参,作用就在于声明在函数内部不会改变这个指针所指向的内容,所以给该函数传一个不可改变的指针(char *p = “linux”;这种)不会触发错误;而一个未声明为const的指针的函数,你给他传一个不可更改的指针的时候就要小心了。
哪个参数做输入哪个做输出?函数传参如果传的是普通变量(不是指针)那肯定是输入型参数;如果传指针就有2种可能性了,为了区别,经常的做法是:如果这个参数是做输入的(通常做输入的在函数内部只需要读取这个参数而不会需要更改它)就在指针前面加const来修饰;如果函数形参是指针变量并且还没加const,那么就表示这个参数是用来做输出型参数的。
内存:
malloc,free bzero
位、字节、半字、字
位(1bit) 字节(8bit) 半字(16) 字(32)
指针高级:
int *p[5] 核心是P,p是一个数组,数组有5个元素,数组中的元素都是指针,指针指向是元素类型是int,是一个指针数组 int(*p)[5]核心是p,p是一个指针,指针指向一个数组,数组有5个元素,数组中的元素都是指针,指针指向的元素是int类型,是一个数组指针
int *(p[]5)与第一个相同
符号优先级[] . ->
typedef
函数指针的书写和分析方法:
void func(void); 对应的函数指针:void (p)(void); 类型是:void ()(void)
b[i] 等同于 *(p+i)
a[i][j]等同于 ((p+i)+j)
二维数组
C语言的字符串类型:
定义字符串的方法:char *p = “linux”,p指向字符串的起始地址
本质:指针指向头,固定尾部的地址相连的一段内存
char *p = “linux” p指针4个字节,”linux”代码段6个字节,’\0’结尾
sizeof、strlen(size_t strlen(const char *s);)
字符数组与字符串的本质差异(内存分配角度)
(1)字符数组char a[] = “linux”;来说,定义了一个数组a,数组a占6字节,右值”linux”本身只存在于编译器中,编译器将它用来初始化字符数组a后丢弃掉(也就是说内存中是没有”linux”这个字符串的);这句就相当于是:char a[] = {‘l’, ‘i’, ‘n’, ‘u’, ‘x’, ‘\0’};
(2)字符串char *p = “linux”;定义了一个字符指针p,p占4字节,分配在栈上;同时还定义了一个字符串”linux”,分配在代码段;然后把代码段中的字符串(一共占6字节)的首地址(也就是’l’的地址)赋值给p。 总结对比:字符数组和字符串有本质差别。字符数组本身是数组,数组自身自带内存空间,可以用来存东西(所以数组类似于容器);而字符串本身是指针,本身永远只占4字节,而且这4个字节还不能用来存有效数据,所以只能把有效数据存到别的地方,然后把地址存在p中。
结构体:typedef
struct 结构体名{
结构体所包含的变量或数组
};
struct stu{
char *name; //姓名
int num; //学号
};
定义结构体的同时定义结构体变量:
struct stu{
char *name; //姓名
int num; //学号
} stu1, stu2;
struct{
char *name; //姓名
int num; //学号
} stu1, stu2 = { “Tom”, 12};
结构体变量来访问元素用. 用结构体变量的指针来访问元素用->
共用体union:
不存在内存对齐的问题,是同一内存空间的多种解释
写一个函数来测试当前机器的大小端模式:
union myunion{
int a;
char b;
};
//union从低地址取
char is_little_endian(void){//小端回1,大端回0
union myunion u1;
u1.a = 1;
return u1.b;//地址0对应的字节为1小端, 高字节对应低地址小端
}
枚举:enum
设有变量a,b,c被说明为上述的weekday,可采用下述任一种方式:
enum weekday{ sun,mou,tue,wed,thu,fri,sat };
enum weekday a,b,c;
或者为:
enum weekday{ sun,mou,tue,wed,thu,fri,sat }a,b,c;
或者为:
enum { sun,mou,tue,wed,thu,fri,sat }a,b,c;
宏定义:
define MAX(a, b) (((a)>(b)) ? (a) : (b))
define SEC_PER_YEAR (365*24*60*60UL)
字符串处理函数:
关键字:
static register auto
extern:主要用来声明全局变量:在b.c 中定义:int g_b = 4; 在a.c中使用:extern int g_b;(外部链接属性)
volatile
链表:
struct node{
int data;
struct node* pNext;
}
struct node* create_node(int data)
{
struct node* p = (struct node*)(malloc(sizeof(p)));
if(NULL == p)
{
printf("malloc error\n");
return NULL;
}
bzero(p, sizeof(struct node));
p->data;
p->pNext = NULL;
return p;
}
void insert_tail(struct node* pH, struct node* new)
{
struct node* p = pH;
while(NULL != p -> pNext)
{
p = p->pNext;
}
p->pNext = new;
}
void insert_head(struct node* pH, struct node* new)
{
new->pNext = pH->pNext;
pH->pNext = new;
}
void reverse_list(struct node* pH)
{
}
struct node* list_3(int* data)
{
struct node* p = (struct node*)malloc(sizeof(struct node));
struct node* pNew;
if(NULL == p)
{
printf("malloc error\n");
return NULL;
}
for(i=0; i<3; i++)
{
pNew = create_node(data[i]);
if(NULL == pNew)
{
return NULL;
}
p->pNext = pNew;
p = p->pNext;
}
return p;
}