一.基本数据类型:
数据类型可以理解为固定内存大小的别名,是创建变量的模子。
变量是一段实际连续存储空间的别名,程序中通过变量来申请并命名存储空间,通过变量的名字可以使用存储空间。
/**********************************************************************************************************************************************/
二.auto,static,register属性修饰符
auto是局部变量的默认属性,存在栈中,可以不写。
static修饰的变量(全局和局部,全局变量本来就存储在静态区)存储在程序静态区
static修饰的另一个意义是文件作用域标识符:
static修饰的全局变量作用域只是在声明的文件中,然而非静态的全局变量在其他源文件中都是有效的
static修饰的函数作用域只是在声明的文件中,其他文件中不能使用,可以用于文件内封装
register关键字指明将变量存储在寄存器中,register只是请求寄存器变量,但不一定成功。
register变量必须是cpu寄存器可以接受的值,不能超出cpu位数的最大值。
不能用&运算符取register变量的地址,因为寄存器变量存储在寄存器中,而&是取得内存地址。
/*************************************************************************************************************************************************/
三.分支循环关键字使用
if:
bool型变量应该直接出现在条件中,不要进行比较,因为bool型变量不在c语言标准中,用户可以自己定义,不一定是0和1.
进行变量和数值比较的时候,数值应该在左边,防止错误
float变量不能和0进行比较,需要定义精度,因为浮点型变量是离散存储的
#define EPSINON 0.00001
float f=0.0;
if((-EPSINON <= f)&&(f <= EPSINON))
{
}
switch
case中的值只能是整型或字符型
if和switch总结:
1. if用于需要“按片”进行判断的情形中
switch用于对各个离散值进行分别判断的情形中
2.if语句可以从功能上代替switch语句,但是switch无法代替if语句
switch语句对于多分支判断更加简洁
do……while(0)的用法:
1.可以消除使用goto,有些函数中,在函数return之前我们经常会进行一些收尾的工作,比如free掉一块函数开始malloc的内存,
goto一直都是一个比较简便的方法:
int foo()
{
somestruct* ptr = malloc(...);
dosomething...;
if(error)
{
goto END;
}
dosomething...;
if(error)
{
goto END;
}
dosomething...;
END:
free(ptr);
return 0;
}
但是使用do{……}while(0)就可以避免使用goto
int foo()
{
somestruct* ptr = malloc(...);
do{
dosomething...;
if(error)
{
break;
}
dosomething...;
if(error)
{
break;
}
dosomething...;
}while(0);
free(ptr);
return 0;
}
2.使用do{……}while(0),定义空宏,避免警告
#define EMPTYMICRO do{}while(0)
3.辅助定义复杂的宏
这样定义一个宏,
#define DOSOMETHING()\
foo1();\
foo2();
本意是使用DOSOMETHING()替代两个函数,但是在某些地方展开的时候,会出现意想不到的后果
if(a>0)
DOSOMETHING();
展开后会是:
if(a>0)
foo1();
foo2();
这就不是我们想要的结果
我们可以采用do……while(0)
#define DOSOMETHING() \
do{ \
foo1();\
foo2();\
}while(0)\
...
if(a>0)
DOSOMETHING();
...
GCC中还可以这样定义:
#define DOSOMETHING() ({\
foo1(); \
foo2(); \
})
/**************************************************************************************************************************************************/
四.goto,void,extern,sizeof
goto:基本不要用
void:
函数没返回值一定要声明为void,因为默认的返回值是int,没有参数也要声明为void
不存在void变量
void指针----》相同类型的指针才能赋值,void类型指针在左值可以接受任意类型的指针,做右值赋值给其他指针要做强制转换。
例如:
extern void *malloc(unsigned int num_bytes); void *memset(void *s, int ch, size_t n);
int* p = (int*)malloc(sizeof(int)); void*指针做内存操作指针的时候,具有普适性。
extern:用于声明外部定义的变量和函数;用于编译器用c的方式编译一段代码
extern “C”
{
……
}
sizeof:不是函数,是内置的指示符,在编译的时候就已经计算出结果,计算变量所占内存的大小,比如以下代码就能看出不是函数:
#include <stdio.h>
int main()
{
int a;
printf("%d\n", sizeof(a));
printf("%d\n", sizeof a);
printf("%d\n", sizeof(int));
return 0;
}
output:4,4,4,但是为了写法统一,都写成带()的形式。
/*************************************************************************************************************/
五.const和volatile
const修饰的变量是只读的,会在内存占用空间,但还是变量,在编译的时候只读,但是运行的时候无效,可以通过运行时的指针来修改。
1 #include<stdio.h>
2 #include<malloc.h>
3 int main()
- 4 {
| 5 const int i=1;
| 6 int *p = (int *)&i;
| 7 printf("%d\n",i);
| 8
| 9 *p = 3;
| 10 printf("%d\n",i);
| 11 return 0;
| 12
| 13
| 14 }
gexueyuan@gexueyuan:~$ ./a.out
1
3
const修饰的数组是只读的,const修饰的数组空间不可改变(有可能程序崩溃,编译器相关)
const int A[5] = {1,2,3,4,5};
int *p = (int *)A;
int i =0;
for(i=0;i<5;i++)
{
p[i] = 5 -i;//有可能会oops,与编译器相关
}
const修饰指针,以*为界,const在左边时修饰指针指向的变量为只读,在右边则修饰指针本身为只读。
const int *p; //p可变,p指向的内容不可变
int const *p; //p可变,p指向的内容不可变
int * const p; //p不可变,p指向的内容可变
const int* const p; //p和p指向的内容都不可变
const修饰函数参数和返回值
const修饰函数参数,表示在函数体内不希望改变参数的值
const修饰函数返回值,表示返回值不可改变,多用于返回指针。
volatile变量是编译器的警告指示字,告诉编译器每次去内存取值,主要用于修饰被多个线程访问的变量
修饰被未知因数修改的变量