003_c语言注意事项

一、printf输出int值

void test02(){
	 int b = 1024;
	 printf("%o\n",b);//2000
	 printf("%x\n",b);//400
	 printf("%X\n",b);//400
	 printf("%8p\n",&b);//这个8位没有生效,输出的还是0x7ffe6c164f24
	 printf("%x\n",&b);//6c164f24
	 printf("%012X\n",&b);//00006C164F24
}

二、int类型数值溢出

void test01(){
	 int a = 0x7fffffff;
	 a = a+3;
	 printf("%d\n",a);//-2147483646
	 /**
		0x7fffffff:0111 1111 1111 1111 1111 1111 1111 1111
		+3        : 0000 0000 0000 0000 0000 0000 0000 0011
					//高位溢出
		            1000 0000 0000 0000 0000 0000 0000 0010
		 1000 0000 0000 0000 0000 0000 0000 0010的原码如下:
		 1111 1111 1111 1111 1111 1111 1111 1101 + 1 =
		 1111 1111 1111 1111 1111 1111 1111 1110           
		 首位是符号位,因此这个数值部分位7fff fffe,即这个数的十进制为-2147483646
	*/
}

三、常量指针和指针常量

void test01() {
	int a = 10;
	const int* p = &a;
	int b = 20;
	p = &b;
	//*p = 100;//IDE提示报错,const位于*之前表示p是指向常量的指针,所以不能通过*p修改p指向地址里面的值

	int* const p1 = &a;
	//p1 = &b;//IDE提示报错,*位于const之前表示p1是指针常量,所以不能修改p1指向的地址,但是可以通过*p1修改p1指向地址里面的值 
	printf("%d %d\n",*p,*p1);
}

四、auto、volatile、register

/*
auto关键字:https://zhuanlan.zhihu.com/p/348520921
有修饰变量生命周期的作用,也有类型推导的作用
volatile关键字:https://zhuanlan.zhihu.com/p/343688629
有禁止编译器优化,以及刷新变量值作用
register关键字:https://zhuanlan.zhihu.com/p/263575137
*/

五、函数指针

int add(int a,int b) {
	return a + b;
}
//返回值类型 (* 自定义类型名称)(参数类型)
typedef int(*FuncName)(int,int);

void test08() {
	FuncName fn = add;
	int(*Fn)(int, int) = add;
	printf("%d %d\n", Fn(100,34),fn(12,22));
}

六、malloc、calloc、realloc

	//开辟一个10字节大小的内存
	int *b = malloc(10);//不会设置内存值为0
	
	//开辟一个4*sizeof(int)字节大小的内存
	int* c = calloc(4, sizeof(int));//会设置内存为0
	//对于b扩容,如果开辟的b后面还有剩余内存的话,则会在b后面紧接着开辟内存内存。
	//如果没有的话,则会全部重新开启内存。把之前b的内容复制过去
	b = (char*)realloc(b,10);

七、字符串数组

void test01() {
	//char a[10] = "hello world"; //报错,字符串常量不能直接赋值给字符数组
	char* str[] = {"ab","cd","123"};
	char* str2[] = { "ab","cd","123" };
	char** st1 = str;
	/*
		打印:ab b cd 123
		*st1:表示常量字符串"ab"的首地址
		*st1+1:表示常量字符串"ab"的第二个字符值
		*(st1+1):表示常量字符串"cd"的首地址
		*(st1 + 2):表示常量字符串"123"的首地址
	*/
	printf("%s %s %s %s\n",*st1,*st1+1,*(st1+1), *(st1 + 2));
}

八、通过内存拷贝获取结构体属性的字符串


typedef struct {
	char* str1;
	int age;
} person_t;

void test01() {
	/*
	* 当前默认的结构体对齐的模数是8,str1的类型是char *,age的类型是int,所以sizeof(p)的值16
	*/
	person_t p = {
	.str1 = "hello world",
	.age = 23
	};

	char** str1 = calloc(1, sizeof(char*));
	/*
		将p在内存中的前8个字节的内容拷贝给二级指针str1。
		因为p在内存中的前8个字节的内容是字符串"hello world"在内存中的地址值,
		所以这个地方要用二级指针来接收
	*/
	memcpy(str1, &p, 8);
	//*str1将会得到"hello world"字符串首个字符的地址值。即p1与p2的值是相等的。
	printf("str1=%s p1=%p p2=%p\n", *str1,*str1, &((*str1)[0]));
	for (int i = 0; i < strlen(*str1);i++) {
		printf("%c\n",(*str1)[i]);
	}
	free(str1);
}

九、关于数组别名步长的问题

void test04() {
	int a[] = {1,2,3,4,5,6,7,8,9,10};

	/*
		a是指向数组首元素地址的指针
		&a是指向整个数组的首地址
		虽然a和&a打印出来的地址值都一样,但是数据类型不一样。
		a是元素指针类型,&a是数组指针类型
	*/
	printf("%p %p\n",a,&a);//000000830F6FF438 000000830F6FF438
	/*
		000000830F6FF438+4=000000830F6FF43C
		000000830F6FF438+28=000000830F6FF460
		因为a指针的指针步长为4,&a的指针步长为40(16进制就是28)
	*/
	printf("%p %p\n", a+1, &a+1);//000000830F6FF43C 000000830F6FF460
	/*
		sizeof(a)是计算整个数组所占内存空间的大小
		sizeof(&a)是计算指针所占空间大小,64位系统,一个地址值所占内存空间大小为8个字节
	*/
	printf("%d %d\n",sizeof(a),sizeof(&a));//40 8
}

十、指针数组与数组指针

/*
数组指针和指针数组
http://c.biancheng.net/view/335.html
*/
void test05() {
	//数组指针
	int(*p1)[5] = {0}; //只允许有一个初始值,多个初始值报错
	//指针数组
	int* p2[5] = {1,2,3};
}

十一、字符串初始化

void test08() {

	char h = 'h';
	char* hp = &h;
	printf("hp=%c\n", *hp);


	char *str1 = "hello world";
	//*str1 = 'h';
	//printf("str1=%c\n",*str1); //抛出异常,字符串常量区的内容不能修改
	
	//报错,buf初始化需要带括号的初始化表达式列表
	//char buf[] = str1;
	
	//这种是可以的
	char buf1[]="hello world";
	
	//不指定长度,没有0结束符,有多少个元素就有多长,所以这样写在memcpy的时候就会报错。因为如果str1长度大于buf申请的
	//长度,那就是非法操作指针了
	//char buf[] = {0};
	
	char buf[100] = { 0 };;
	memcpy(buf,str1,strlen(str1));
	buf[0] = '2';
	printf("buf=%s\n", buf);
	
	char buf2[100]={'h','e','w'};//没有赋值的自动以数字0填充
	
}

十二、字符串结束符0的区别

void test07() {
	char buf1[] = {'q','b','c',0,'1','3'};
	//字符0是起不到结束字符串的作用
	char buf2[] = { 'q','b','c','0','1','3' };
	char buf3[] = { 'q','b','c','\0','1','3' };

	printf("buf1=%s\n",buf1); //qbc
	printf("buf2=%s\n", buf2); //qbc013乱码
	printf("buf3=%s\n", buf3);//abc
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值