C语言你不得不知道的小知识:
1: 常见的变量修饰关键字:static、const、extern、volatile、register
static:(该变量保存在全局静态区)
a.修饰局部变量——>会提升局部变量的生存周期(此时局部变量可以理解为全局变量)
b.修饰全局变量——>作用域被限制——>被限制到当前的原文件中 c.修饰函数——>作用域被限制——>被限制到当前的原文件中
const:(该变量保存在常量区)
1.声明常变量,,使得指定的变量不能被修改。
2.修饰函数形参,使得形参在函数内不能被修改,表示输入参数。
3.修饰函数返回值,使得函数的返回值不能被修改。
extern: 用于修饰变量或函数,表明该变量或函数都是在别的文件中定义的,提示编译器在其他文件中寻找定义。
volatile: 强制编译器每次从内存中取得该变量的值,而不是从被优化后的寄存器/缓存中读取。
register:(该变量保存在寄存器中)
用来声明为寄存器变量。也为局部变量,只在声明它的函数内有效。它是保存在寄存器之中的。速度要快很多。
2: 一个程序占用的内存通常分为以下几个部分:代码区、常量区、全局(静态)存储区、堆区、栈区
代码区:
存放程序编译后的二进制代码【代码】
常量区:
存放只读变量和字符串常量,一经初始化,不可修改.【const变量、字符串】
全局(静态)存储区:
全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,
未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。因此,又可以分为.data段和.bss段。
.data段 (数据段):
存放已初始化的全局和静态变量。在编译器编译的时候,会给已初始化的数据分配内存空间,数据保存在目标文件中。
.bss段 (bss段):
(bss是英文Block Started by Symbol的简称。)存放未初始化或初始化为0的全局和静态变量。在编译器编译的时候,不会给该段的数据分配空间,只是记录数据所需的空间大小。
堆区:
由程序员手动申请/释放,若不手动释放,程序结束后由系统回收.【malloc申请的内存,用完一定要free释放掉】 效率高, 向下压栈, 占用空间小
栈区:
由系统自动分配/释放,存放函数参数,局部变量等.【局部变量、函数参数、数组等】 自由度大,向上存放数据, 占用空间大
3:
指针函数:一个函数,它的返回值是指针。
函数指针:一个指针,它指向一个函数。
【指针函数】定义形式:
类型 *指针变量名 (参数列表):
例如:
int *p(int i, int j);
说明:
p是一个函数,该函数有2个整形参数,它的返回值是一个指针,指向一个整数类型。
因为()的优先级比*更高,所以可以写成:int *(p(int i,int j)),
表明它是一个函数,返回值是一个指向整型的指针。
【函数指针】定义形式:
类型 (*指针变量名)(参数列表);
例如:
int (*p)(int i,int j);
说明:
p是一个指针,它指向一个函数,该函数有2个整形参数,返回类型为int。
p首先和*结合,表明p是一个指针。然后再与()结合,
表明它指向的是一个函数。指向函数的指针也称为函数指针。
表明它是一个函数,返回值是一个指向整型的指针。
4:指针与const关键字
a)char * const p;
b)char const *p;
c)const char *p;
d) char const* const p;
分析:
a)一个指针,指向char数据类型,p是常量。【指针不可更改】
b)一个指针,指向char数据类型,p指向的数据是常量。【所指的内容不可更改】
c)一个指针,指向char数据类型,p指向的数据是常量。(char放在前后都没关系)
d)一个指针,指向char数据类型,p是常量,p指向的数据也是常量。【指针和所指向的数据都不可更改】
总结: const在*左边:内容不可改变
const在*右边:指针不可改变
5: 指针与数据类型
问题:
a) 一个整型数(An integer)
b)一个指向整型数的指针( A pointer to an integer)
c)一个指向指针的的指针,它指向的指针是指向一个整型数( A pointer to a pointer to an intege)r
d)一个有10个整型数的数组( An array of 10 integers)
e) 一个有10个指针的数组,该指针是指向一个整型数的。(An array of 10 pointers to integers)
f) 一个指向有10个整型数数组的指针( A pointer to an array of 10 integers)
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer)
h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer argument and return an integer )
i) 一个函数,该函数的参数是整数类型,该函数的返回值是指针。
答案:
a)int p;
b)int *p;
c)int **p;
d)int p[10];
e)int (*p[10]);
f)int (*p)[10];
g)int (*p)(int);
h)int (*p[10])(int);
i)int *p(int);
6:善用位运算,如下:
a=a%8; (前提是2的倍数)
可以改为:
a=a&7; (a=a&(8-1))
位操作只需一个指令周期即可完成(更贴近于代码语言),而大部分的C编译器的“%”运算均是调用子程序来完成,代码长、执行速度慢。
善用移位实现乘除法运算,如下:
a=a*4; (a * 2^2)
b=b/4;
可以改为:
a=a<<2; (左移)(a * 2^2)
b=b>>2; (右移)(a / 2^2)
通常如果需要乘以或除以2n,都可以用移位的方法代替。用移位的方法得到代码比调用乘除法子程序生成的代码效率高。实际上,只要是乘以或除以一个整数,均可以用移位的方法得到结果,如:
a=a9
可以改为:
a=(a<<3)+a (a * 2 ^3)+ a
7:字符数组初始化与不初始化的区别
/*server.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define M 3
#define Y(n) ((M + 1)*n)
int main()
{
int n = 3;
int size = 0;
char a[20];
printf("a %d\n", strlen(a));
for (int j = 0; j < 10; j++) {
a[j] = '0';
}
printf("a %d\n", strlen(a));
printf("a %s\n", a);
char b[20] = {0}; // 等价于初始化为'\0'
printf("b %d\n", strlen(b));
for (int j = 0; j < 10; j++) {
b[j] = '0';
}
printf("b %d\n", strlen(b));
printf("b %s\n", b);
int z = 2 * (M + Y(5 + 1)); // 2 * (3 + (3 + 1)* 5 + 1) = 48
printf("z is %d", z);
return 0;
}
8:回调函数
回调函数:就是一个通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
函数指针也是一种指针,只是它指向的不是整型,字符型而是函数。函数指针就是通过指向这个函数的入口,从而调用这个函数。
函数指针定义:
void (*p_func)(int, int, float) = NULL;
函数指针的赋值:
p_func= func1 (或者 p_func = &func1)
使用数指针调用函数:
int res = p_func(1, 2, 3.0)
使用函数指针作为参数传给函数:
void func4(int a, int b, float c, void (*p_func)(int, int, float)){
(*p_func)(a, b, c);
}
func4() {
func3(1, 2, 3.0, func1);
}
四则运算的具体实例:
float ADD(float a, float b) {
return a + b;
}
float SUB(float a, flloat b) {
return a - b;
}
float MUL(float a, float b) {
return a * b;
}
flaot DIV(flaot a, float b) {
flaot a / b;
}
typedef struct OP {
float (*p_addfunc)(int, int, float)
float (*p_subfunc)(int, int, float)
float (*p_mulfunc)(int, int, float)
float (*p_divfunc)(int, int, float)
} OP;
void initOP(OP* op)
{
op->p_addfunc = ADD;
op->p_subfunc = SUB;
op->p_mulfunc = &MUL;
op->p_delfunc = &DIV;
}
float mul_opretion_func(float a, float b, (*p_func)(int, int)) {
return (*p_func)(a, b);
}
int main()
{
mul_opretion_func(1.0, 2.0, op->p_addfunc);
mul_opretion_func(1.0, 2.0, op->p_subfunc);
mul_opretion_func(1.0, 2.0, MUL);
mul_opretion_func(1.0, 2.0, DIV);
}
9:C语言的库函数
常见的使用
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
int main()
{
int a = 221;
char s[123] = {0};
char* ss = (char*)malloc(123 * sizeof(char));
sprintf(s, "%d", a);
strcpy(ss, "aaa");
strcat(s, "bbb");
printf("%s\n", s);
printf("%s\n", ss);
int s_len = strlen(s);
printf("s len is %d\n", s_len);
char* sss = (char*)calloc(123, sizeof(char));
memset(sss, 0, 123 * sizeof(char));
printf("%s\n", sss);
strcpy(sss, "aaavvvv");
printf("%s\n", sss);
return 1;
}