c/c++语言开发共享C基础补习

1: gcc 默认编译生成 a.out—-可以自己指定 调试信息:直观的打印输出信息 printf("file = %s,line = %d,func = %sn",__

1:
gcc 默认编译生成 a.out—-可以自己指定

调试信息:直观的打印输出信息
printf("file = %s,line = %d,func = %sn",__file__,__line__,__func__);

__file__ :当前文件名 –%s
__line__ :当前行号 –%d
__func__ :当前函数 –%s

2:关键字:

数据类型关键字:(5)

void

char

int

float

double

类型修饰关键字: (4)

short

long

signed

unsigned

复杂类型关键字: (5)

struct

union

enum

typedef

sizeof

存储级别关键字: (6)

auto

static

register

extern

const

volatile

流程控制关键字: (4)

return

continue

break

goto

分支结构关键字: (5)

if

else

switch

case

default

循环结构关键字: (3)

for

do

while

3:数据类型长度:sizeof() 字节数

基本类型 (32位) (64位系统)

char : 1 1

short (int) : 2 2

int : 4 4

long (int) : 4 8

long long (int): 8 8

char * (指针) : 4 8

float : 4 4

double : 8 8

4:数据类型转换:

double ← float

unsigned long ← long

unsigned ←unsigned short

int ← char , short

5:进制标识:

八进制: 0开头
二进制: 0b开头
十六进制: 0x开头

6:负数在计算机内的存储格式:

1.先忽略负号直接将其绝对值转换为二进制
2.再取反二进制

3.最后再加1就是其存储值

 

int c = -7;//0x000000007(绝对值)—0xfffffff8(取反)—0xfffffff9(加1)

printf("signed c = %#xn",c);

 

结果是:

signed c = 0xfffffff9

 

7:小数(float double)的存储方式:

符号位 指数位底数位
float 1 + 8 + 23
double 1 + 11 + 52

8.25
1.整数部分:8—1000

8 / 2 = 4 — 0 ↑

4 / 2 = 2 — 0 ↑

2 / 2 = 1 — 0 ↑

1 / 2 = 0 — 1 ↑

2.小数部分:0.25 — 01

0.25 * 2 = 0.5 –0 ↓

0.5 * 2 = 1 –1 ↓

3.结果是:1000.01
4.转换为符号和指数与底数模式
1.00001 * 2^3 (底数:00001 指数:3 + 127(01111111) = 130 — 10000010)
符号位1 指数位8位底数位23
5.计算机存储数据为– 0 10000010 0000 1000 0000 0000 0000 000

 

-8.25

符号位1 指数位8位底数位23

计算机存储数据为– 1 10000010 0000 1000 0000 0000 0000 000

举例:
-12.5

第一步:1100.1 = 1.1001 * 2^3

第二步:符号位 1,指数: 3 + 127 = 130 (10000010),底数: 1001

第三步:1100 0001 0100 1000 0000 0000 0000 0000

第四步:0xc1 48 00 00

17.625

第一步:10001.101 = 1.0001101 * 2^4

第二步:符号 0 ,指数: 4 + 127 = 131 (10000011) 底数: 0001101

第三步:0100 0001 1000 1101 0000 0000 0000 0000

第四步:0x 41 8d 00 00

8:>> <<
>>(算术右移)
低位抛弃
无符号数:高位全部补0
有符号数:负数(高位全部补1),正数(高位全部补0)
int c = -7;//0x000000007(绝对值)—0xfffffff8(取反)—0xfffffff9(加1)
int d = 1000;//0x0000003e8(绝对值)

printf("signed c = %#xn",c >> 4);
printf("signed d = %#xn",d >> 4);

结果是:
signed c = 0xfffffff9
signed d = 0x0000003e

<<(算术左移)
低位全部补0

9:需要注意的运算符号:

表达式1 && 表达式2 (若1为假将不执行2)
表达式1 || 表达式2 (若1为真将不执行2)

异或
a^a=0;
a^0=a;

三目运算符:
表达式1 ? 表达式2 : 表达式3–(若1为真将返回2,否则返回3)

逗号:
表达式1,表达式2,,表达式3,……,表达式n (最后的值是表达式n的值)

10:for循环执行步骤:

for(int i=0;i<20;i++){

循环体
}

执行步骤是:
1、i=0 初始化初值;
2、进行条件判断i是否<20,如果条件为真,则继续执行;
3、执行循环体的代码;
4、i++ 变量i自增一次;
5、回到第2步,一直循环,直到第2步条件为假时, 退出循环,结束

11:printf()函数注意点:

printf(""); (运算从右到左,打印输出从左到右)

比如:
int i = 10;
printf("%d,%dn",i++,i);

1.其先从右边计算i为10
2.再计算i++表达式值为10
3.结果输出为10,10
————————
int i = 10;
printf("%d,%dn",i,i++);

1.其先从右边计算i++为10,但是i变成了11
2.再计算i已为11

3.结果从左边开始输出为11,10

 

12:三大结构:
顺序,选择,循环

switch(表达式){//表达式的结果必须是整型值或者字符型值,否则报错

case 'a' :
….;
break;
case 1 :
….;
break;
……
default :
….;
}
—————–
if(){

} else if (){

} else {

}
————
循环语句:
while(){} //先判断再执行

do{}while(); //先执行一次再判断

for(;;){} //执行步骤在 九

continue;(结束本次循环,继续下次循环)
break;(跳出当前整个循环)
return;(结束当前函数,并且返回一个值)

13:变量的存储周期与作用域:

普通局部变量:存储周期(模块内,模块执行完成就销毁),作用域(模块内)
普通全局变量:存储周期(整个程序期间),作用域(所有模块)

静态变量(static修饰):不同模块定义的将会被存储在不同区域,也就是代表不同变量
局部:存储周期(整个程序期间),作用域(模块内)
全局:存储周期(整个程序期间),作用域(所有模块)

局部变量 会 局部屏蔽 同名 的 全局变量

比如:

int a = 1;//全局变量

int main(){

printf("%dn",a);

int a = 10;//属于main{}内的局部变量,它将在main中屏蔽前面定义的int a=1

printf("%dn",a);

{//这大括弧不加的话,系统报错,认为有两个cc同时存在
int a = 100; //这个a就是{}局部变量,只在这个{}之间使用
printf("%dn",a);
}
a++;
printf("%dn",a);

return 0;
}
结果输出是:
1
10
100
11

14:指针:

int a = 10;
(int *)p = &a; (int *) 为指针符号

b = *p; (此时*p为 a的值,表示将a赋给b)
*p = 100; (此时*p指向a,代表a的存储空间,以后a就为100)

指针的类型: int *
指针指向的类型: int

野指针:
指针定义后若没有指向变量地址,
此时它就只是一个单一变量,
其值随机,
访问它非常危险!
int *p = null;(避免危险,空指针不能访问)

char *p, t; (表示p为指针变量,t表示char 变量)
char *p, *t;(表示p与q都是指针变量)

15:指针的运算:

int a[10];//数组在内存中存储是连续的

int *p = &a[0];
int *q = &a[8];

p + 1;
p + 1 – 1;

指针 加减(地址偏移) (偏移量:n * sizeof(*p)—与指针指向地址存储数据类型有关)
p++,++p (*p++,*++p)
p–,–p (*p–,*–p)
p – q, q – p (个数(矢量-有正负))

(*p)++;
表示将p指向地址空间的内容加 1,
以后p指向的地址空间的内容在随后使用中都被改变了的,
指针没有发生偏移
*p++; //*(p++)
先取出当前指针指向内存地址的数值,
再将p指向的地址偏移一个存储单位
*++p; //*(++p)
先将p指向的地址偏移一个存储单位
再取出偏移后指针地址的数值,

注意:运算过程中 p 与 *p 的区别运算符的优先级等

16:内存开辟函数:

(void *) 解引用之前必须先类型强制转换

比如:
int main(){

int a = 10;
void *p = null;

p = &a;//任何指针都可以赋给void *指针

printf("%dn",*p);//该语句错误,*p 在这里直接解引用了一个void *指针
printf("%dn",*(int *)p);//这里是先将void *指针p强制转换为int *指针,再对其解引用,无误

return 0;
}

下面的这些函数返回值都是定义的void * ,所以在解引用时要先强制转换

p = malloc(a);
分配a个字节空间
返回这个空间的地址指针 p
这个空间没有初始化,其值为随机数,常使用memset(p,20,'0')来初始化
若a = 0 则返回 null 或者一个确定的唯一指针,让free释放

free(p);
释放函数创建的指针p指向的空间

p = calloc(a,b);
分配a个b大小的存储空间
返回这个空间的地址指针p
初始化为0
若a = 0 则返回 null 或者一个确定的唯一指针,让free释放

p = realloc(q,a);
重新分配大小
返回原有地址指针

比如:
int main{

int *p = null;

p = (int *)malloc(100);//因为malloc返回的是void * 类型,这里就将它强制转换为int * 了,后面可以直接使用

*p = 100;

printf("%d,%pn",*p, p);

return 0;
}

17:指针指向 字符串常量 与 字符数组 的区别:

char *s = "12345";
s就是指向一个字符常量"12345",
常量是不能够修改的,所有s[2]='e';或者*(s+1) = 'e';的操作都是错误的

char s[10] = "12345";
char *p = s;
s 是一个字符数组,可以修改
此时指针p可以去修改了,*(p+1)='e'; 相当于s[1]='e';

18:二级指针:

必须存储一个地址的地址(也就是一级指针的地址)
比如:
int a =10;
int *p = &a; //p存储的是a的地址,指向a
int **q = &p; //q存储的是p的地址,指向p

*q 表示解引用,取p存储的值,也就是a的地址
*(*q) 同理

19:指针数组:

定义的数组元素为指针

(char *)b[10];
数组b的类型为指针类型,
也就是说数组b中定义的10个元素都是指针类型

char *b[10] = {"abcd","hello","efgh"}; 特别注意点: 其中元素都是字符串常量,只能根据地址读取,不能修改其值
上面语句相当于:
char *b[10] = {null};

b[0] = "abcd"; //b[0]指向字符串首地址
b[1] = "hello"; //b[1]指向字符串首地址
b[2] = "efgh"; //b[2]指向字符串首地址

也就是将指针指向一个个字符串常量,常量是不能修改的,只能读取
*(b[2]) = 'q';这样的赋值语句就会出现段错误
———————-
可以修改为如下:
char *b[10] = {null};

char s1[4] = "abcd";
char s2[5] = "hello";
char s3[4] = "efgh";

b[0] = s1;
b[1] = s2;
b[2] = s3;

此时是将指针指向字符数组,就可以通过指针修改数组!
*(b[0] + 1) = 'd';就s2[1]修改了
*(*(b + 2) + 2) = 'a';就将s3[2]修改了
———————————-

b[0],b[1],b[2]….都是代表对应的首地址
比如:
b[0]–(&a), b[1]–(&h)
b[0]+1,b[0]+2,b[1]+1,b[1]+2…也是代表地址(地址偏移)
比如:
b[0]+1–(&b), b[0]+2–(&c), b[2]+1–(&f)

b,b+1,b+2,b+3…都是代表 地址的地址
比如:
b–(&b[0]), b+1–(&(b[1])), b+2–(&(b[2]))

所以有:
*(b+3) :b+3 代表b[3]的地址(&b[3]),对其解引用 b[3](还是地址) 则 *(*(b+3)) 为 *b[3] (null (自动补0的原因))

20:数组指针:

指向一维数组的指针 int (*p)[];

int a[3][4];
int (*p)[4];

将二维数组a[3][4]看做
a[0]:(a[0][1],a[0][1],a[0][2],a[0][3])
a[1]:(a[1][1],a[1][1],a[1][2],a[1][3])
a[2]:(a[2][1],a[2][1],a[2][2],a[2][3])

其中a[0],a[1],a[2]都是表示其对应的一维数组的首地址
a可以看做 数组a[0],a[1],a[2]的首地址,a指向a[0]

a[0],a[1],a[2]也都表示首地址

p代表a[0]地址,p+1代表a[1]地址,p+2代表a[2]地址
a[0]+1代表a[0][1]地址 ,a[2]+2代表a[2][3]地址
*(a[0]+1)表示a[0][1]
*(*(p+1)+1) 表示a[1][1]

举例
int main(){

int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,0,10,11}};
int (*p)[4] = a;

printf("%d,%d,%dn",**p, *(*(p + 1) +1), *(*p + 1));

//*p指向a的首地址,**p就是a[0]数值
//p + 1 指向a[1]的首地址,*(p + 1)就是a[1]的首地址,再对其加1,地址偏移到a[1][1],解引用为a[1][1]
//*p指向a[0]的首地址,*p + 1指向a[0][1],*(*p + 1))就是a[0][1]
return 0;
}

21:绝对地址写数据:

向绝对地址 0x12345678 写入字符 'a'
char *p = (char *)0x12345678;//强制转换
*p = 'a';

向绝对地址 0x12345678 写入int型 1000
char *p = (int *)0x12345678;
*p = 1000;

22:

extern 声明外部变量

static :
修饰全局变量:
只能在该模块被使用 (普通全局变量在整个程序中能被任意模块使用)
修饰局部变量:
生命周期变为静态 (普通局部变量的生命周期为定义到该模块结束)
修饰函数:
该函数只能在该模块被调用

const :
修饰变量:
常变量,该变量只能在定义的时候初始化,其他任何时候都不能直接去修改它的值
可以通过指针去间接修改
比如:
int main(){

int const a = 10;
int *p = &a;

a = 100;//该语句会提示错误,因为a是常变量
*p = 100;//指针可以修改,但是会提示警告

printf("%dn",a);

return 0;
}

const全局变量存储在全局存储空间,其值只有可读属性,不能修改;

比如:
int const a = 10;
int *p = &a;

int main(){

a = 100;//该语句会提示错误,因为a是常变量
*p = 100;//该语句也会错误

printf("%dn",a);

return 0;
}

const局部变量存储在堆栈中,可通过指针修改其值;

const变量在预处理是处理,编译器只对其值读取一次。

修饰函数:其他模块不能使用该函数

const int *p;
const 修饰的是 指针*p 代表地址存储的值,也就是说指针p指向的地址内的值不能通过 指针p 去修改
但是 p 可以重新指向其它地址

int *const p;
const 修饰的是 变量p 代表地址,也就是说 p指向的地址不能改变,也就是说不能将这个指针变量指向其它地址
但是可以通过 *p 来修改其地址内的值

volatile :

23:函数传参:

单向的值传递–传入的值在函数中改变后,在退出函数后,改变的值不会返回
int main(){

int a =10;
int b = 100;

printf("%d,%dn",a,b);//10,100

fun(a,b);//11,101–函数里面对a,b进行处理,但是离开这个函数就没有影响a,b的值

printf("%d,%dn",a,b);//10,100

return 0;
}
int fun(a,b){

++a;
++b;
printf("%d,%dn",a,b);

return 0;
}

传地址:传首地址与数据个数–改变了传入的值

int main(){

int a = 10;
int b = 100;

printf("%d,%dn",a,b);//10,100
fun(&a, &b); //11,101 –通过地址改变值
printf("%d,%dn",a,b); //11,101 –结果都改变了,双向传输

return 0;
}
int fun(int *p, int *q){

*p = 11;
*q = 101;
printf("%d,%dn",*p, *q);

return 0;
}

24:sizeof() 字节数 注意点:

int a = 10;
int b[10] = {1,2,3,4};
char *c = "12345";

printf("%d,%d,%dn",sizeof(a), sizeof(b), siezof(c));
//sizeof(a) :a是int 类型 4字节
//sizeof(b) :b数组10个int类型的元素 4 * 10= 40 字节
//sizeof(c) :c代表字符串首地址,是一个地址,32位系统地址 4字节

特别的:
int fun(int a[100]){//这里的int a[100] 等价于 int *a

printf("%dn",sizeof(a)); //所以也是一个地址 4字节

return 0;
}

25:

printf(); 输出到终端
i,d :十进制整数
x,x :十六进制无符号整数
o :八进制无符号整数
u :无符号十进制整数
c :单一字符
s :字符串
e,e :指数形式浮点小数
f :小数形式浮点小数
g :e和f中较短一种
%% :% 本身
————
m :数据宽度,m小于实际长度将按照实际长度输出
.n :
对实数:指定小数位
对字符串:指定实际输出位
– :左对齐
+ :有符号数正数显示+号
0 :左边补0
# :加0,0x
l :指定输出精度
————-
int a = 100;

printf("%#5.3lxn",a);

fprintf();输出到文件
sprintf(); 指定格式转换到指定字符串
snprintf();

atoi(); 指定字符串转换为int
int main(){

char *s = "1357";//若char *s = "13a7";会自动切断a和其后面数据,输出13
int ss = 0;

ss = atoi(s);
printf("%dn",ss);//输出 1357

return 0;
}

atol(); 指定字符串转换为long
atoll(); 指定字符串转换为long long
atop(); atoll()函数的老式名称

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/606938.html

(0)
上一篇 2021年5月14日
下一篇 2021年5月14日

精彩推荐