C语言深度剖析笔记

本文深入讲解C语言中的变量定义与声明,探讨八进制常数的潜在风险,介绍sizeof运算符的使用规则,并讨论了signed、unsigned关键字的应用。此外,还涉及循环语句的注意事项、const关键字的理解、枚举与#define的区别,以及整数除法和余数的特性和指针相关的易错点。
摘要由CSDN通过智能技术生成

1.变量定义:所谓的定义就是(编译器)创建一个对象,为这个对象分配一块内存并给它取上一个名字,这个名字就是我们经常所说的变量名或对象名。

2.变量声明:1.告诉编译器,这个名字已经匹配到一块内存上了,下面的代码用到变量或对象是在别的地方定义的。声明可以出现多次。
2.告诉编译器,这个名字已被预订了,别的地方再也不能用它来作为变量名或对象名。
定义变量规则:禁止使用八进制的常数(0除外)在计算机中,任何1以0开头的数字都被认为是八进制格式的数(当然十六进制的0x不算)。所以,当我们写固定长度的数字时,会存在一定的风险。举例如下:
code[1] = 109;//对应十进制的109
code[2] = 100;//对应十进制的100
code[3]=052; // 对应十进制的42,因为052是以0开头,以八进制形式存储。
code[4] = 071;//对应十进制的57
在转义字符中后面跟八进制数,用于表示ASCII码等于该值的字符,使用时也可能
会出现意想不到的错误
code[6] = ‘\100’;存储的值可能为64

sizeof:
sizeof在计算变量所占空间大小时,括号可以省略,而计算类型大小时不能省略。且一般情况下,sizeof是在编译时求值,所以sizeof(i++)不会引起副作用。但由于sizeof(i++)与sizeof(i)的
结果一样,所以没有必要且不允许写这样的代码。
注意:在用sizeof测字符串长度时,会算上’\0’结束字符的长度,但是如果把字符串以单个字符的形式存在数组中时不会算’\0’的长度。
而在用strlen测时不会算上’\0’的长度。

#include <stdio.h>
		#include <string.h>
		int main()
		{
			char s1[]="abcdefg";
			char s2[]={'a','b','c','d','e','f','g'};
			printf("%lu\n",sizeof(s1));
			printf("%lu\n",strlen(s1));
			printf("%lu\n",sizeof(s2));
			printf("%lu\n",strlen(s2));
			return 0;
		}
	结果是:8 7 7 7

signed、unsigned关键字
32位的signed int 类型整数,其值表示的范围为:-231~(231-1)
32位的unsigned int 类型整数,其值表示的范围为:0~(2^31-1)
例:

int main()
	{
		signed char a[1000];
		int i;
		for(i = 0;i<1000;i++)
		{
			a[i] = -1-i;
		}
		printf("%d",strlen(a));
		return 0;
	}
	答案是255;

分析:for循环内,当i的值为127时a[127]=-128,而-128是char类型数据能表示的最小的负数,当i继续增加时a[128]的值肯定不能是-129,这时发生了溢出,最高位被丢弃,剩下的8位是原来9位补码的低8位的值,即0x7f。当i继续增加到255的时候,-256的补码的低8位为0;然后当i增加到256时,-257的补码的低8位全为1,即低8位的补码位0xff,如此又开始一轮新的循环,因此a[255]=0;strlen函数遇到’\0’结束 因此是255;

循环语句的注意点:
1.在多重循环中,如果可能,应当将最长的循环放在最内层,最短的循环放在最外面,以减少CPU
跨切循环层的次数。
2.建议for语句的循环控制变量的取值采用"半开半闭区间写法"
3.不要再循环内部修改循环变量,防止循环失控。
4.把循环嵌套控制在3层以内。
5.for语句的控制表达式不能包含任何浮点型的对象。
const:定义const只读变量,具有不可变性。
“近水楼台先得月”
const int p;//const修饰p,p是指针,*P是指针指向的对象,不可变
int const *p;同上
int *const p;//修饰的是p,p不可变,p指向的对象的值可变
const int * const p;//都不可变
一、枚举与define的区别:
1.#define 宏常量是在预编译阶段进行简单替换,枚举常量则是在编译的时候确定其值。
2.一般在调试器里,可以调试枚举常量,但不能调试宏常量。
3.枚举可以一次定义大量相关的常量,而#define宏一次只能定义一个。

二、
\ddd
1~3位八进制数所代表的字符
\xhh
1~2位十六进制数所代表的字符

三、贪心法:
每一个符号应该包含尽可能多的字符。
四、2/(-2)的值为多少?
经测试2/(-2)为-1,2%(-2)为0。
q = a/b;
r = a%b;
1.我们希望q*b+r==a
2.如果我们改变a的正负号,希望q的符号也随之改变,但q的绝对值不会变。
3.当b>0时,我们希望保证r>=0且r<b。
这三条性质是我们认为整数除法和余数操作所应该具备的。但是,很不辛,它们不可能同时成立。
因此,C语言在实现整数除法截断运算时,必须放弃上述3条性质中至少1条。大多数编程语言选择了放弃第3条。
五、一些容易出错的优先级问题

在这里插入图片描述
一、指针
1.一个基本的数据类型(包括结构体等自定义类型)加上号就构成了一个指针类型的模子。这个模子的大小是一定的,与"“号前面的数据类型无关;”*“号前面的数据类型只是说明指针所指向的内存里存储的数据类型。所以在32位系统小,不管什么样的指针类型,其大小都为4字节。可以测试一下sizeof(void *)
int main()
{
char *p = NULL;
int *p1 = NULL;
long *p2 = NULL;
printf(”%lu\n",sizeof§);
printf("%lu\n",sizeof(p1));
printf("%lu\n",sizeof(p2));
return 0;
}
结果: 8 8 8 (64位系统)
2.int p = NULL和p = NULL的区别
int p = NULL;
定义一个指针变量p,其指向的内存里面保存的是int类型数据;在定义变量p的同时把p的值设置为0x00000000,而不是把
p的值设置为0x00000000、这个过程叫初始化,是在编译的时候进行的。
int *p;
p = NULL;
第一行代码定义了一个指针变量p,其指向的内存里面保存的是int类型的数据;但是这时候变量p本身的值是多少不得而知,也就是说现在变量p保存的可能是一个非法的地址。第2行代码,给
p赋值为NULL,即给p指向的内存赋值为NULL;但是由于p指向的内存可能是非法的所以调试的时候调试器可能会报告一个内存访问错误。
将代码改写一下:
int i = 10;
int *P = &i;
*p = NULL;
发现p指向的内存由原来的10变为0了;而p本身的值,即内存地址并没有改变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值