1. main函数
-
main
函数返回值
(1)main
函数是整个程序的入口,其他函数只能被main
函数直接或间接调用才能执行,main
函数开始意味着程序的开始,结束返回代表整个程序结束;
(2)main
函数的执行本身就是一个进程,因此main
函数是被它的父进程所调用,返回值给它的父进程。 -
main
函数的参数
(1)main
函数的参数由调用它的父进程传入,并给它的父进程返回值;main
函数传参不是必须的,如int main(void){return 0;}
(2)给main
传参通过argc
和argv[]
这两个C语言预订的参数来实现,
int main(int argc, char *argv[])
,argv[]
是字符串数组(指针数组)类型,里面存的多个字符串;argc
是整型,代表argv[]
中的字符串的个数;
(3)给main
函数传参时,都是字符串;各个参数之间通过空格隔开;若使用argv[]
,需要先检查argc
int main(int argc, char *argv[])
5 {
6 printf("params num = %d\n", argc);
7 int i;
8 for(i = 0; i < argc; i++)
9 {
10 printf("argv[%d] = %s\n",i, argv[i]);
11 }
12 return 0;
13 }
book@www.100ask.org:~/test1$ ./main abc 3f fa
params num = 4
argv[0] = ./main
argv[1] = abc
argv[2] = 3f
argv[3] = fa
2. “空”
-
函数类型的本质
(1)代表该类型的存储空间大小和解析方式,若无类型则会导致编译器无法分配空间和无法解析该变量;
(2)对于内存而言并没有类型的区别,因为内存只负责存放二进制数据,而存放大小和解析方式由编译器决定; -
void
类型的本质
void
类型不代表没有类型,而是代表未知类型,将来可以通过强制类型转换将void
类型转换为任何的数据类型,单独定义void a;
无意义且会报错;多用在指针的应用上
void *malloc(size_t size) //malloc的原型
char *p = (char *)malloc(40); //返回char*类型的指针
- NULL
(1)NULL
的标准定义: C++的编译环境中,编译器预先定义了一个宏_cplusplus
,程序中可以用条件编译来判断当前的编译环境是C++的还是C的。
#ifdef _cplusplus //如果是C++
#define NULL0
#else //如果是C
#define NULL ((void *)0)
#endif
(2)NULL
的本质是指针p
指向了0
地址,大部分的CPU中,0
地址处不可以随便访问,所以指针指向了这个区域可以保证野指针不会造成误伤。如果程序无意识的解引用,指向0
地址处的野指针则会触发段错误。
int *p = NULL; //int *p = (int *)0;
if (NULL == p)
{}
(3)一般判断p
不是野指针时,再解引用p
,注意判断时NULL == p
而非 p == NULL
,NULL
是常量不可以赋值,可以避免NULL = p
的失误;
3. const关键字
const
关键字修饰哪一个变量取决于其后紧跟的变量,若有 *
则修饰的是指针指向间接变量,无 *
则指向直接变量。
const
与指针
const int* p1
:修饰*p1
,指针p1
为普通变量,p1
指向的数据*p1
为只读变量;
int const* p2
:修饰*p2
,指针p2
为普通变量,p2
指向的数据*p2
为只读变量;
int* const p3
:修饰p3
,指针p3
为只读变量,p3
指向的数据*p3
为只读变量;
const int* const p
:同时修饰p和*p, 二者皆为只读变量。const
与typedef
int main(void)
{
int a = 5;
int b = 10;
typedef const int* tint; //const修饰间接变量,即int*指向的空间
tint p = &a;
*p = 10; //报错
typedef int* const pint; //const修饰直接变量
pint t = &a;
*t = 10;
t = &b; //报错
typedef int* pint; //const修饰直接变量
pint t1 = &a;
*t1 = 10;
t1 = &b; //报错
}
- 修改
const修饰的变量是否可以修改也不同,取决于编译环境,可以通过指针的间接访问方法修改const修饰的变量,在gcc下可以,在vc++下不行
const int f = 5;
int *p = &f;
*p = 3;
printf("func = %d\n", f);
//结果输出为func = 3
意义
(1)const
修饰的变量的意义更多的是表明该变量没有修改的必要,而并非代表着无法修改,C语言语法并未强制要求;
(2)对于const
关键字的检测是在编译器层面进行的,只要通过编译器,就可以修改。
4. 大小端模式
- 大端模式:高字节存放在低地址;小端模式:高字节存放在高地址
如0x12345678
在内存byte0, byte1, byte2, byte3中的存放方法
大端模式:
0x12 | 0x34 |
---|---|
byte0 | byte1 |
0x56 | 0x78 |
byte2 | byte3 |
- 通过程序确定大小端
可以通过共用体或指针确定
/**通过共用体**/
//定义共用体
union str{
int a;
char c;
}s1;
//判断
int func(void)
{
s1.a = 1;
return s1.c
}
int main()
{
int i = func(void);
if(i == 1) //小端模式
printf("小端模式\n");
else
printf("大端模式\n");
return 0;
}
/**通过指针**/
int func(void)
{
int a = 1;
char *pc = (char *)&a;
return *pc;
}
int main(void)
{
int i = func();
if(i == 1)
printf("小端模式\n");
else
printf("大端模式\n");
return 0;
}
注意:通过位与、移位、强制类型转换的方式是无法确定大小端,因为位操作与强制类型转换都是编译器层面进行的,而不是内存层面进行的;
/******************以下方法都是错误的********************/
//位操作:编译器会自动将a取出来并将a与0xff相与/右移1位/强制类型转换,不涉及内存,与a存放在高地址还是低地址无关
int a = 1;
int b = a & 0xff;
int b = a >> 1;
int b = char(a);
if(b = 1)
printf("小端模式\n");
else
printf("大端模式\n");