C语言学习中遇到的小知识点

 1.欲戴王冠必承其重

2. ++i和i++只在赋值方面有区别

3.异或,相同为假,不同为真

4.x*=y+z等价于x=x*(y+z)

即复合的赋值运算中,等号右面的表达式带括号。

5.%2c%3c%4c

若输出abcdefgh

输出acf

6.按位与&左右同时检查。

逻辑与&&先检查左值,在检查右值。

逻辑或||先检查左值,左值真,不检查右值;

左值假,检查右值。

&判断的过程如1&3à

其实是二进制位操作001

                                 011

                                 001==1

所以1&3是真

0&3à

000

011

000==0

所以0&3为假

7.在求解一个数各个位置的数字时,

可以通过“/”和“%”混用,快速求解

如4567求解百分位

4567%1000/100

8.常变量的值不会改变

const int a=3;

9.++k自带赋值功能,所以以下代码与想表达意思不同

int k, sum=0;

    for (k = 1; k <= 5; k++)

        sum = sum+k * (++k);

    printf("%d", sum);

10.升序是小的在上面

11.字符数组进行赋值时,scanf函数或gets函数整体赋值,要注意scanf和gets函数的区别,在对字符串赋值时,scanf函数不能出现空格(系统把空格字符作为输入的字符串之间的分隔符)

12.scanf(“%s”)如果输入时结尾用回车键确认,则输入缓冲区中有一个回车需要被吃掉。如果有空格将输入的分成几部分,则只输入空格之前的部分,其他的在缓冲区内,可以通过

while(ch=getchar()!=’\n’)

{

;

}

来吞掉后面的字符。

其中如果通过

Scanf(“%[^\n]”,arr)进行输入,则与

Gets(arr)相同,意为遇到\n后停止

13.二分查找算法

数组内数字按大小有序排列,

取中间数与要查找的数比较

通过比较结果确定下一范围

14.计算数组大小

sizeof(arr)/sizeof(arr[0])

//其中在函数中不可以计算数组大小,因为实参传递给形参的实际上是数组首地址,是一个指针,占四或八个字节,在主调函数中求得。

//二维数组行数

Sizeof(arr)/sizeof(arr[0])

二维数组列数

Sizeof(arr[0])/sizeof(arr[0][0])

字符数组最右边下标

sizeof(arr)/sizeof(arr[0])-1

字符串数组最右边字符下标

sizeof(arr)/sizeof(arr[0])-2

或strlen(arr)-1

15.<windows.h>

Sleep();//括号内毫秒,指休息几毫秒

<stdlib.h>

system(“cls”);执行系统命令的一个函数—cls—清空屏幕

16.二进制转化成八进制

二进制转化成十六进制

转义字符的ASCII码

17.switch case 语句中,如果不加break,以符合要求的一项为开始向下运行到结束。

其中如果default也在后面,则执行,如果不在后面,在符合要求的一项前面,则不执行。

18.printf的返回值是打印字符的个数。%d算一个,直接打印的字母算一个,汉字算两个。

Scanf的返回值是读取了几个数值(几个%d被使用了,返回几),读取失败返回EOF.

19.数组名做函数实参不能加[ ],

    数组名做函数形参必须加[ ].

20.求两个数最大公约数,辗转相除法

即24、18

24%18=6

18%6=0  则6是最大公约数

21.局部变量不初始化,是随机值。//栈区

全局变量不初始化,默认是零。//静态区

静态变量默认也是零。

22.%p以16进制打印地址

23.二维数组列不能省略

24.数组名就是数组首元素地址

有两个例外

  1. sizeof(数组名),数组名不是数组首元素的地址,数组名表示整个数组。
  2. &数组名,数组名不是数组首元素的地址,数组名表示整个数组,取出的是整个数组的地址。

25.对于二维数组a[3][3]

sizeof(a)=9  sizeof(a[0])=3

strlen(a)一直找到\0,strlen(a[1])从a[1]开始一直找到\0

26.rand()%100+1 生成1~100之间的随机数或者理解成%100后一定0-99然后加1

其中的rand()%(n-m+1)+m算是一个公式(上限-下限+1)+下限

比如产生10~30的随机整数:srand(time(0));

int a = rand() % (21) + 10;

27.初始化二维数组时,如arr[3][4]

如果想第二行全为零,

不可{{1},{},{4,6,9,10}}//即第二行空着

此不合法。

应该{{1},{0},{4,6,9,10}}//给个零

28.负数的原码,反码,补码转换

即补码取反后加一也可以得到原码

(补码的补码就是原码)

29.右移操作符

30.按位与 按位或 按位异或

都是以二进制补码形式操作

其中a^a=0  0^a=a

异或操作符只能作用于整数

31.sizeof()括号内的表达式是不参与运算的

如a=3

Sizeof(a=a+3)

结果还是a=3

原因是编译期间就处理了sizeof,

不会在运行时执行a=a+3了

32.scanf()读取失败的时候,返回EOF

EOF实际上是-1

而While(~scanf(“%d”,&n))之所以可以终止循环,是因为返回的EOFà-1二进制取反=0

33.下边引用操作符[ ]

arr[4]<=>*(arr+4)<=>*(4+arr)<=>4[arr]

[ ]是操作符

34.整型提升

当运算类型为整型,且字节数小于int型时,运算时会先转换为int型或unsigned int,然后才能送入CPU运算。

通用CPU操作数字节长度一般是int的字节长度

35. 全局变量,没有给初始值时,编译其会默认将其初始化为0。

36.sizeof()的返回值是无符号整型

37.

 

Visual studio编译器,先执行全部a++或++i,然后再相加

38.指针类型作用

(1)指针类型(int* char*等)决定了在解引用指针变量时,访问的权限,即所操作的字节大小

如int* 可操作四个字节,

char* 只能操作一个字节

(2)指针类型决定了指针向前或向后走一步,走多大距离

对指针操作时

即int*p;p+1向后四个字节 +1—>+1*sizeof(int)à+4

Char*p;p+1 向后一个字节+1—>+1*sizeof(char)à+1

39.指针-指针

得到的是指针之间元素的个数

或负个数

40.二级指针

41.指针数组

存放指针的数组

42.调试时F5(调试)和F9(设置断点)一般配合使用

43.形参数组中[ ]的值不需要设置,即使设置了,也没用,不会在函数中创建数组,

还是按传递过来的数组名是首地址进行操作。

44.栈地址的使用是由高地址向低地址使用的。

45.十六进制 两位 占一个字节

即一个int型数据如10

00000000 00000000 00000000 00001010

用00 00 00 0a即可表示

46.

小端字节序存储,

把一个数据的低位字节处的数据存放在低地址处,

把高位字节处的数据存放在高地址处

大端字节序存储,

把一个数据的低位字节处的数据存放在高地址处,

把高位字节处的数据存放在低地址处

Visual Studio采用的小端字节序存储

如存取数字10,

转化为16进制为00 00 00 0a

在内存中存储

0x008FFBA4  0a

0x008FFBA5  00

0x008FFBA6  00

0x008FFBA7  00

47.数组

小下标在低地址,大下标在高地址

即数组随着下标的增长,地址是由低到高变化的

48.const

Const int a=10;

不能对a进行赋值操作

但是*(&a)可以修改a的值

Const在*左边

如Const int* p=&num;或int const*p=&num;

Const修饰的是*p,p指向的对象不能通过*p改变,但可以改变p中的地址

Const在*右边

如Int* const p=&num;

Const修饰的是p,不可以改变p中的地址,但p指向的对象的值能通过*p改变

49.输出八进制%o,输出16进制%x,

可以用%#o控制输出0的前导0

可以用%#x控制输出0x的前导0x

%X(大写的X)可以控制输出的16进制字母为大写的

50. 浮点数比较大小

不可以float f=0.000001

然后if(f==0.000001)//==不可用于浮点型。

因为0.000001没有在内存中精确存储

应该写成

float a = 0.000001f;

 float b = 0.000001f;

//abs是绝对值

//1e-6是上下浮动数字

 if (abs(a - b) <= 1e-6) {

  printf("a 等于 b\n");

 }

 else {

  printf("a 不等于 b\n");

 }

51.字符指针的另一用法

指将字符串abcdef的a的地址给p

Ps:abcdef创建出来就被放在了常量区

字符串abcdef是常量字符串

为了保证不 改变常量abcdef而报错

可以在char前面加上const

如果出现两份常量字符串abcdef

如const char*p1=”abcdef”;

Const char*p2=”abcdef”;内存中,常量区只保存一份,即p1和p2所指向地址相同

52.二维数组中,如果列越界访问,可以访问到对应元素,因为二维数组在内存中是连续存放的

int a[2][2] = { 1,2,3,4 };

    printf("%d", a[0][2]);

将会输出3

53.数组指针

Int * p[10]叫指针数组

Int(*p)[10]叫数组指针

P是数组指针类型

即int(*)[10]

//[10]表示p指向的数组有多大,int表示p指向的数组元素是什么类型

练习

54.二维数组中

数组名表示的是第一行的地址

类型是

如int a[3][5]

其中a的类型为int(*p)[5]

55.isalpha()          //<ctype.h>

判断括号内是否为字母

如果是,返回一个非0的值

如果不是,返回0

56.scanf运用%m格式控制,可以控制输入的域宽。

如输入20040328

可以通过scanf(“%4d%2d%2d”)依次将2004 03 28截取下来

57.printf运用%0格式控制,可以用0来填充不足域宽的部分

如Printf(“%02d”,3);

将输出03

58.sizeof的返回值是无符号整型

59.当不同类型进行运算时,要进行算术转换,算术转换是向上,向高字节转换的。

其中,如果整型和无符号整型进行运算时,整型转换成无符号整型

如int a=-1;

If(-1>sizeof(a))

Printf(“hehe”);

就结果来看,是会输出hehe的

因为sizeof返回值为无符号整型,

-1进行算术转换

补码11111111 11111111 11111111 11111111

看成无符号整型

60.n=n&(n-1)的妙用

//每次运算使n的二进制形式末尾少一个1

(1)求一个整数以二进制存储有多少个1

(2)求一个整数是不是2的幂次方

           //看看二进制是否只有一个1

61. 
//int arr[5];

//arr是一个整形数组,每个元素是int类型的,有5个元素

//int* parr1[10];

//parr1是一个数组,数组10个元素,每个元素的类型是int*

//int(*parr2)[10];

//parr2是一个指向数组的指针,指向的数组有10个元素,每个元素的类型是int

//int(* parr3[10])[5];

//parr3 是一个数组,数组有10个元素,每个元素的类型是:int(*)[5]

//parr3是存放数组指针的数组

62.c语言中不能&(&a)

因为&的操作数必须是

一元&运算符的操作数应该是函数指示符,[]或一元*运算符的结果,或者是一个左值(变量)

63.函数指针

    //int(*p)(int, int) = &Add;

    int(*p)(int, int) = Add;//Add和&Add都代表Add函数地址

    int ret = (*p)(2, 3);//(*p)就是Add

    //int ret = p(2, 3);//p就是&Add

    //int ret = Add(2, 3);

    //int ret = ( * Add)(2, 3);//由于Add是地址,(*Add)就是Add

    //int ret = (&Add)(2, 3);

    printf("%d", ret);

64.函数声明可以不写形参,只写形参类型

65. 回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一 个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

66.void*类型的指针可以接收任意类型的指针而不报错(垃圾桶)

但不能对void*类型的指针进行

解引用 和 加1操作

使用之前要进行强制类型转换

67.sizeof(1)结果为4,即整型1的大小

Int a[10];

Sizeof(a+0)结果为4或8,即数组a首地址大小

Strlen

比较strlen和sizeof

68.二维数组

如a[3][4]

可以理解成三个一维数组组成的二维数组

一维数组名分别是a[0],a[1],a[2]

Ps:sizeof()括号中实际上是检测类型

如int a;

Sizeof(a)等价于sizeof(int)

上图最后一个

Sizeof(a[3])等价于sizeof(int[4]),虽然越界了,但实际上sizeof没有直接访问

69.

Ps:%p是以地址形式打印,不是去找地址,

所以给一个整型数,就以地址形式打印他

同时%p会在32位机器上打印4字节内容

64位打印8字节内容,不够位数补零

Ps:%x以16进制打印,不补零

70.

71.二维数组可以用二级指针方式解引用

如a[3][5]

a第一行的地址

*a第一行第一列的地址,相当于a[0]及第一行数组名

**a通过*a第一行第一列地址,找到首元素

72.pow()求幂函数

返回值是double类型的

73.字符数组没有完全初始化,未初始化部分默认为\0

74.strlen的返回值是无符号整型size_t

75.strcpy的返回值是目标空间的起始地址

76.strcat的返回值是目标空间的起始地址

77.数组指针解引用,相当于数组名,即首元素地址

78.strncpy如果源字符串长度小于给定num,拷贝完源字符串后,在目标字符串追加\0,直到达到num

79.strncat如果源字符串长度小于给定num,

只会拷贝完源字符串。

.strncat拷贝完num长度的源字符串后,会在目标字符串后面追加一个\0

80.strncmp中num表示比较前几个字符

81.strstr找子串

char * strstr ( const char *str1,

const char *str2 );

在str1中找str2,返回str1中第一次出现str2的地址

82.strtok分割

char* strtok(char * str,const char * sep)

sep参数是个字符串,定义了用作分隔符的字符集合

str指定一个待分割的字符串

strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改 变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)

strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。

 strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。

 如果字符串中不存在更多的标记,则返回 NULL 指针。

83.当库函数调用失败时,会将错误码存入一个名为errno的全局变量中

84.strerror

char* strerror(int errnum);

返回错误码所对应的错误信息

返回值是错误信息字符串起始位置的地址

85. 字符分类函数     <ctype.h>

 如果他的参数符合下列条件就返回真 (非零)

如isdigit(‘4’)返回非零数

iscntrl 任何控制字符

isspace 空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v'

isdigit 十进制数字 0~9

isxdigit 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F

islower 小写字母a~z

isupper 大写字母A~Z

isalpha 字母a~z或A~Z

isalnum 字母或者数字,a~z,A~Z,0~9

ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)

isgraph 任何图形字符

isprint 任何可打印字符,包括图形字符和空白字符

字符转换

 toupper()  小写转大写

 tolower()  大写转小写

86.内存操作函数

一.memcpy 内存复制

void * memcpy ( void * dest, const void * src, size_t num );

num是待拷贝内存的字节数

如果src和dest有任何的重叠,复制的

结果都是未定义的

(但其实有的编译器已经可以在重叠

情况下进行复制了)

二.memmove 内存复制

void * memmove ( void * dest, const           void * src, size_t num );

可实现src和dest重叠时的拷贝

三.memcmp 内存比较

       int memcmp ( const void * ptr1, const

void * ptr2, size_t num );

    比较ptr1和ptr2每个字节的大小,比较num个字节,

ptr1>ptr2 返回大于0

ptr1=ptr2 返回0

ptr1<ptr2 返回小于0

四.memset 内存设置

void *memset( void *dest, int c, size_t count );

                         目的地       设置的字符  设置几个字节

以字节为单位初始化内存

87.

匿名结构体是省略结构体标签的结构体

两个匿名结构体即使成员一样,在编译器看来也是不同的结构体

88.结构体内存对齐

1. 第一个成员在与结构体变量偏移量为0的地址处。

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8

3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

89. 修改默认对齐数

#pragma pack(8)//设置默认对齐数为8

struct S1

 {

char c1;

int i;

char c2;

};

 #pragma pack()//取消设置的默认对齐数,还原为默认

90.位段

       位段是为了节省空间的一种,类似于结构体类型的类型

     特点:成员是有或无符号整型int,unsigned int,char

                     成员名后面又一个冒号和数字

                     空间的开辟是以一个字节或四个字节开辟的

位段是不跨平台的,注重可移植的程序应该避免使用位      段

数字代表所占比特位

struct S

{ char a:3;   char b:4;    char c:5;    char d:4; };

91.联合体(共用体)

1联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小

2联合体内的成员不会同时使用

3 联合体也存在对齐

   union Un1

{

 char c[5];//5,对齐数1

 int i;//4,对齐数4

 };

联合体大小八个字节

92.动态内存管理     #include<stdlib.h>

malloc  void *malloc( size_t size );

              返回开辟空间的起始地址,申请失败返回NULL

free     void free( void *memblock );

一般free(p);之后要p=NULL;//因为此时p还是指向原位置,只是该程序不用了

如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。

如果参数 ptr 是NULL指针,则函数什么事都不做

Free无法释放动态开辟内存的一部分

如果申请动态内存,却没有释放,

如果程序结束,系统会自动释放,

如果程序未结束,不会自动释放,导致内存泄漏(内存占用)

calloc    void *calloc( size_t num, size_t size );

                                   开辟个数   开辟大小

              返回开辟空间的起始地址, 申请失败返回NULL

              calloc会自己初始化,将开辟的内存赋值为0

realloc   再开辟(扩容)  (也能调小)

              void *realloc( void *memblock, size_t size );

                                   已开辟空间起始地址  总空间字节大小

              返回扩容后空间的起始地址, 申请失败返回NULL

          

情况1 当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。

情况2 当 是情况2 的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来 使用。这样函数返回的是一个新的内存地址。

如果realloc(NULL,20),则相当于malloc(20)

93.printf(“hehe”);实际上是把hehe的首地址传了进去

       所以若char *p=”hehe”;printf(p);也能正常打印

94.柔性数组

C99 中,结构中的最 后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。

结构中的柔性数组成员前面必须至少一个其他成员。

sizeof 返回的这种结构大小不包括柔性数组的内存。

包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应 柔性数组的预期大小。

95.printf(“%02x”)代表以十六位进制打印,打印两位,不够补0

96. int atoi( const char *string );

              将数字字符串转换成整型。

字符串中可以有负号,返回整型负数

字符串中可以有其他字符,遇到其他字符截至

(持续更新中2023.9.16)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值