首页 > 其他分享 >c 理解

c 理解

时间:2023-02-13 11:45:21浏览次数:55  
标签:const 函数 int void 理解 位域 指针

exit() 的含义:提前结束程序 .c 文件

return的含义 :提前结束函数,其所在行以下,整体大函数底花括号以上,2者之间的所有语句都不会被执行到,用它来提前结束程序。

break的含义 :提前结束其所在的本层循环

continue的含义 :提前结束其所在的本次循环

 

 

Static与Const的区别

1、static 局部变量 将一个变量声明为函数的局部变量,那么这个局部变量在函数执行完成之后不会被释放,而是继续保留在内存中,其值是可随时变得,只是内存空间不释放,下次在用此内部变量时其值为上次结束时的值。

2、static 全局变量 表示一个变量在当前文件的全局内可访问,值可变。

3、static 函数 表示一个函数只能在当前文件中被访问

4、static 类成员变量 表示这个成员为全类所共有

5、static 类成员函数 表示这个函数为全类所共有,而且只能访问静态成员变量

 

static 关键字的作用:

1、函数体内static变量的作用范围为该函数体,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值(值可变);

2、在模块内的static全局变量和函数可以被模块内的函数访问,但不能被模块外其它函数访问;

3、在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;

4、在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。

 

enum 关键字的作用:

1、不同枚举中的名字必须互不相同, 同一枚举中不同的名字可以有相同的值.

2、枚举类型:指一个被命名的整型常数的集合。即枚举类型,本质上是一组常数的集合体,只是这些常数有各自的命名。枚举类型,是一种用户自定义数据类型。

3、枚举变量:由枚举类型定义的变量。枚举变量的大小,即枚举类型所占内存的大小。由于枚举变量的赋值,一次只能存放枚举结构中的某个常数。所以枚举变量的大小,实质是常数所占内存空间的大小(常数为int类型,当前主流的编译器中一般是32位机器和64位机器中int型都是4个字节),枚举类型所占内存大小也是这样。

 

const 关键字的作用:

1、const 常量:定义时就初始化,以后不能更改。

2、const 形参:func(const int a){}; 该形参在函数里不能改变

3、const 修饰类成员函数:该函数对成员变量只能进行只读操作

4、const char * :const在 * 前边,所以叫常量指针,即一个指向不可变的常量的指针,一个指向char类型的指针且不能更改指向地址上的值(const char *p 等价 char const *p)。

5、char * const : * 在 const 前边,所以叫指针常量,即一个值是固定值的指针变量,即不能更改指向的地址。

 

const 和 #define 的区别

1、const定义的常量时带类型, define不带类型。

2、const是在编译、运行的时候起作用:而define是在编译的预处理阶段起作用。

3、define只是简单的替换,没有类型检查。简单的字符串替换会导致边界效应。

4、const常量可以进行调试的, define是不能进行调试的,主要是预编译阶段就已经替换掉了,调试的时候就没它了。

5、const不能重定义,不可以定义两个一样的,而define通过undef取消某个符号的定义,再重新定义。

6、由于const常量一旦被创建后其值就不能再改变,所以const常量必须在定义的同时赋值(初始化),后面的任何赋值行为都将引发错误。初始化const常量可以使用任意形式的表达式,既可以在运行时初始化也可以在编译时初始化。

  举例:

  int n = 90;

  const int MaxNum1 = getNum(); //运行时初始化

  const int MaxNum2 = n; //运行时初始化

  const int MaxNum3 = 80; //编译时初始化

 

 

define 关键字的作用:

1、通常宏定义出现在 .h头文件之中,也就是说在其他文件中只要你包含了这个头文件,你就可以用此宏定义了;如果是定义在 .c文件之中的,那就只能在该c文件中使用了。

2、#if !defined symbol 等价 #ifndef symbol (如果没定义symbol则…)

3、宏定义加括号可使其为一整体,不用考虑宏带入后的优先级错误。eg:若 Define a 2+3 则 2*a == 7;若 Define a (2+3) 则 2*a == 10

 

define 和 typedef 的区别:

1、typedef是给已存在的重命名,而define可在任何条件下重命名。

2、typedef int hh ->hh a; 等同于 int a;

3、typedef char hhh[6] ->hhh a; 等同于 char a[6];

4、typedef char(hhh)[6] -> hhh b 等同于 char b[6];

5、typedef (*ccc)(char c) -> ccc是一个 只有一个char形参的函数指针,调用函数指针执行具体的函数时,函数指针前加不加*都可以。

6、define 之后第一个连续的字符串(由字母数字下划线构成,\拼接不起效) 等同于后面的一堆 (\拼接起效)

7、typedef 最后一个连续的字符串 等同于中间的一堆。

8、没有赋值的宏在预处理时会被删掉, 比如 #define FUCK if(1==FUCK)就会变为if(1==)会报错。但是作为#if define FUCK的判断依旧会成立

 

#include 或 #define 中 ‘#’ 的作用:

1、表示编译预处理,#开始的语句是在编译器开始编译之前由编译预处理程序先进行处理,比如#include 就是将include后面的头文件内容插入到include 语句处

2、#用在预编译语句里面可以把预编译函数的变量直接格式成字符串;注意,不能直接在其它非预编译函数直接使用#a的形式,假如main函数里面出现printf("the square of " #x " is %d.\n",(x)*(x))是不能通过编译的.而#define  Func1(x)  printf("the square of "#x" is %d.\n",(x)*(x))是对的

3、##是宏连接符,作变量链接; #用来把参数转化为字符串。 eg:#define HHH(n) int##n 则HHH(32)就等同于int32

 

 

inline 关键字的作用:

1、inline函数调用时,不需要繁琐的入栈、出栈过程,这一点相对于普通函数执行效率会高很多;

2、inline函数在编译时,会将函数体指令码直接插入到调用点,这样函数的调用更加简单,但是如果调用点多的话,会增加代码体积;相比于宏,inline函数是函数,可以单步调试,宏是在预编译过程中直接替换文本;

3、虽说inline函数执行时效率高,但是不能把所有的函数都写成inline函数,一般inline函数里面不能有循环语句,一般是把频繁调用且简短的代码写成inline函数。

 

extern 关键字的作用:

1、函数本身不加任何修饰的话就是extern的,加上extern的修饰会加速程序的预处理,而全局变量在定义文件外引用就需要此修饰变量。

2、在函数使用的地方,extern函数名可以不用管函数具体定义位置,也不用包含相应头文件,即可使用。

 

sizeof关键字的作用:sizeof是运算符,不是函数名。

uint8_t *Number = "ASDASD"; sizeof(Number)==4。 strlen(Number)==6。

uint8_t Number[] = "ASDASD"; sizeof(Number)==7。 strlen(Number)==6。

uint8_t Number[10] = "ASD"; sizeof(Number)==10。 strlen(Number)==3。

uint8_t Number[]="0X36,0X16,0X0D,0X0A"; sizeof(Number)==5,strlen(Number)==4。

uint16_t a[10]; sizeof(a)==20。uint32_t a[10]; sizeof(a)==40。

 

sizeof(char) = 1; sizeof(char *) = 4; sizeof(int) = 4;

 

int a sizeof(a) = sizeof(int) = 4;

 

char a[] = hello; char *p = a; sizeof(p) = 4;

 

sizeof(*p) = sizeof(“hello\0”) = 6;

 

所有字符数组在定义时,长度必须比实际需要的长1,以自动补充一个‘\0‘,方便字符操作函数strcat,strlen等的处理。后补的字符串会自动覆盖前面字符串的'\0'。

结构体的大小只能用sizeof,而不能用strlen。

 

void 关键字的使用规则:

1、如果函数没有返回值,那么应声明为void类型;

2、如果函数无参数,那么应声明其参数为void;

3、如果函数的参数可以是任意类型指针,那么应声明其参数为void * ;void*的指针变量是指此指针变量可以被赋予任意类型的指针值,而不是说void*的指针变量可以指向任何数据类型。viod*只传递地址值,不具有指向功能。所以形参是void*的函数,被调时会被赋予一个指向具体数据类型的指针,但在调用函数中不能直接引用此形参指针,须在被调函数中定义个与实参同类型的指针,然后将形参指针的值赋予被调函数中定义的指针,然后操作此指针。如果形参是指向具体类型的指针就不必再定义同类型指针传递,而是直接操作此行参即可。

4、void不能代表一个真实的变量;

 

void 的含义:

1、void的字面意思是“无类型”,void *则为“无类型指针”,void *可以指向任何类型的数据。

2、void几乎只有“注释”和限制程序的作用,因为从来没有人会定义一个void变量

void真正发挥的作用在于:

1、对函数返回的限定;

2、对函数参数的限定。

 

' : ' 是c中位域的运算符;而 ' : : ' 是c++的运算符,' : : ' 结合方向是向左关联,' : : '表示作用域,和所属关系。' : : ' 是c++运算符中等级最高的,它分为三种:

1、全局作用域符, 用法( :: name)

2、类作用域符,用法(class :: name)

3、命名空间作用域符,用于局部变量和全局变量重名时的区分,用法( :: name)

 

calloc 与 malloc 函数的作用:

1、calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据;同时申请完内存空间后必须要检测返回值是否=NULL,防止内存泄露。

2、同时在函数内定义的变量和数组,只有在函数执行完毕退出时才会被自动释放,当发生函数调用时主调函数变量和数组所占的内存空间不会释放,同时被调函数中定义的也会同时开辟空间,但是函数内部通过诸如以上的关键字主动申请的内存在函数结束时是不会自动释放的,必须手动释放。

 

memset 函数的作用:

memset(a,1,20):就是对a指向的内存空间从前往后数的前20个元素所占字节全赋值为数值1,即0x01,而不是字符‘1’。

 

Struct :结构体内的成员在内存中是连续存储的,类似数组;但如果结构体内有指针,则指针的位置只占4字节,它只是指向另外一片连续的空间,而不是把这个空间整体放到指针的位置。对于任意的结构体变量a,可以通过&a来获取首地址,等同于结构体内第一个元素的首地址。

 

位域:有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:

  struct 位域结构名

    {位域列表 };

  其中位域列表的形式为: 类型说明符 位域名:位域长度

  例如:

  struct bs

  {

    int a:8; (低位)

    int b:2; | 注:定义时行号的递增对应实际地址的递增

    int c:6; (高位)

  };

  位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如:

  struct bs

  {

    int a:8;

    int b:2;

    int c:6;

  }data;

  说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明:

  1、一个字节所剩空间不够存放另一位域时,应从下一字节起存放该位域。也可以有意使某位域从下一单元开始。例如:

  struct bs

  {

    unsigned a:4 /* unsigned即为unsigned int */

    unsigned :0 /* 空域 */

    unsigned b:4 /* 从下一单元开始存放 */

    unsigned c:4

  };

  在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。

  2、位域中各位段赋值时,直接赋予一个不超过位宽的值即可,不用考虑此位段的偏移量。例如:b直接赋予[0,15]即可,不必[0,15]<<8。

  3、位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。

  struct k

  {

    int a:1

    int :2 /*该2位不能使用*/

    int b:3

    int c:2

  };

  从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的

 

函数指针与指针函数:

void (*fun)(void*):fun不是函数名而是个函数指针,指向一个具有参数是viod*,且返回值是void的函数。(函数指针)

void * fun(void*): fun是个函数名,这个函数的参数是void*,函数返回一个viod*的指针;等同于(void*)fun(void*)。(指针函数)

 

1、大量数据通过 a.txt 文件引入程序的方式:

  1、a.txt中存入格式 ("hello word"); 必须有()和 " "

   程序中: print 此行不需要 ' \ '

   #include a.txt 等同于print(“hello word”);

   若文件中没有;号,则在代码下行写入;号

   2、a.txt中存入“hello word”则引用字符串方式为:

   const char *p =

   #include a.txt

   ;   // 必须单写一行

   print(“%s”, p);  则输出 “hello word” 

 

2、函数体的 { } 分别对应压栈和出栈操作,{ } 内定义的变量只能在 { } 内使用, 函数的形参属于局部变量也只能在 { } 内起效,多个形参从右向左压入栈。 形参对应的实参是在主调函数体内定义的栈变量,而不是在被调函数中定义的。

 

标签:const,函数,int,void,理解,位域,指针
From: https://www.cnblogs.com/lance9527/p/17115648.html

相关文章