C语言学习中容易疏漏的地方总结
知识点①:输出、输入函数格式化占位符和格式修饰符的使用
%c 一个字符
%d 十进制整数 %ld:长整型 %lld:longlongint %hd:shortint
%i十进制整数
%o 八进制整数
%x,%X十六进制整数
%s 一个字符串,遇空格、制表符或换行符结束。
%f,%F,%e,%E,%g,%G用来输入实数,可以用小数形式或指数形式输入。
%p 一个指针
%u 读入一个无符号十进制整数%zd:无符号长整型unsignedlong
%n 至此已读入值的等价字符数
%% 读%符号
printf()函数格式修饰符说明:
最小宽域m(整数):
指定输出是所占的列数;若m是正整数,当输出数据宽域小于m时,在域内向右靠齐,左边多余位补空格;当输出数据宽域大于m时,按实际宽度全部输出;若m有前导符0,则左边多余位补0;若m为负整数时,则输出数据在域内向左靠齐。
显示精度.n(大于等于0的整数):
精度修饰符位于最小宽域之后,由一个圆点及其后的整数构成,对于浮点数,用于指定输出的浮点小数位数;对于字符串,用于指定从字符串左侧开始截取的子串字符个数。
*:
最小宽域m和精度.n用代替时,表示他们的值不是常数,而由printf()函数的输出项按顺序依次指定
#:修饰格式符f、e、g时,用于确保输出的数据有小数点,即使无小数位时,也是如此修饰格式符x时,用于确保输出的十六进制数前带有前导符0x.
scanf()函数格式修饰符:
忽略输入修饰符*:表示对应的输入项在读入后不赋值给相应的变量。
知识点②:经常使用代码块{}及时释放不需要的变量占用的内存。
知识点③:(面试用)奇葩的交换两个整数的方法。
奇葩一:
a = b - a;
b = b - a;
a = b + a;
奇葩二
:
a = a^b;
b = a^b;
a = a^b;
知识点④
:
scanf
("%d%d");
如果格式串中有空格
可以用空格、
tab
、回车
知识点⑤:取余运算%的结果与被除的符号相同结果为两个正数取余后前面加符号
知识点⑥:sizeof运算符
sizeof是一种运算符不要想当然理解为函数
sizeof使用时可以不加()
sizeof可以加变量、常量、数据类型
跟数据类型是必须加()
知识点⑦:if后面直接定义变量引起的问题
if (10 > 6)
int a = 5;//错误*****作用域
//如果在if后面定义新的变量必须用大括号
下面的也是同样的错误
char c ='+';
int a = 10;
int b = 20;
switch(c)
{
case '+':
int sum= a + b;//错误******作用域
printf("和是%d\n",sum);
break;
case '-':
intminus = a - b;//错误
printf("差是%d\n",minus);//错误
break;
}
//修改 如果要在case后面定义新的变量必须用{}包住
switch(c)
{
case '+':
{
int sum = a + b;
printf("和是%d\n",sum);
break;
}
case '-':
{
int minus = a - b;
printf("差是%d\n",minus);
break;
}
}
同样的,for循环后面没有{}也不能定义变量
for(int i = 0; i< 10; i++, a++)//这样有错误 作用域
{
inta = 10;
}
知识点⑧:C语言可以在for中初始化计数变量//性能好,怎么我记得当时学得不可以 C++可以
for(int i=0;...;...)
//
对比
int i = 0;//这种情况下使i在内存停留的时间太长
while(i...)
知识点⑨
:
for
初始参数作用域问题
for(int i = 0; i< 10; i++)//作用域 这样是对的 循环体执行10次
{
inti = 10;
}
//
相当于
for(int i = 0; i < 10; i++)
{
inta = 10;
}
for(int i = 0; i< 10; i++, a++)//这样有错误 作用域
{
inta = 10;
}
//下面有错误 作用域
for(int i = 0; i< 10; i++, a++)//这样有错误 作用域
{
int a = 10;
}
知识点⑩:逗号表达式的陷阱
例如:
for (int i=0,j=0;...;...)不能写成for (int i=0,int j=0;...;...)//逗号表达式的使用
知识点
⑪
:C语言不允许两个函数名字一样 不存在重载的概念
函数不可以重复定义 但是可以重复声明
知识点⑫:#include编译预处理命令与多文件团队开发
#include编译预处理命令可以认为是:将后面的文件内容拷贝到当前的文件中
多文件团队开发:模块分别编译成.o都不能链接成功,合起来链接生成最终程序。
链接:把项目中所有相关联的.o目标文件、C语言函数库合并在一起,生成可执行文件
1.函数的定义放.c文件,函数的声明放.h文件
2.如果要使用某个.c文件中定义的函数,只需要#include这个.c文件对应的.h文件
3..h文件的作用:被别人拷贝。编译链接的时候不需要管.h文件
知识点⑬:数组初始化:这个我真没见过
int ages[5] = {[3] = 19, [4] = 20};
这个是可以的
int ages[] = {19,20};
下面这样是不对的:
intages[5];
ages = {19, 20, 21, 22, 23};//数组名 是地址
//下面
这样是可以的
int count = 5;
int ages[count];//
ages[0] = 10;
ages[1] = 11;
ages[2] = 12;//但是ages[3]ages[4]的值是随机的
//下面
这样是不对的:
int count = 5;
int ages[count]= {10,11,12};//error
结论:如果在定义数组的时候进行初始化,数组元素必须是常量,或者不写
知识点⑭:计算数组长度
sizeof(数组名)/sizeof(数组名[0])
sizeof(数组名)/sizeof(数组类型)
知识点
⑮
:数组作为函数参数时 在函数内部无法计算数组的长度
因为传递参数时
数组被当做指针,在C语言中64位的编译器环境下指针变量的长度始终是8字节
因此在传递参数要传递数组长度
知识点16:字符串初始化
//以下前四种都是字符串
char name[8] ="it";
char name2[8] ={'i', 't', '\0'};
char name3[8] ={'i', 't', 0};
char name4[8] ={'i', 't'};
//
这样不可以
char name4[] = {'i','t'};//不是字符串
//理解字符串在内存中的存储
char name[] ="it";
char name2[] ={'o', 'k'};
printf("%s\n",&name2.[1]);//kit
知识点17
:strlen函数
1.计算的字符数:"哈haha"长度是7
2.计算的字符不包括'\0'
3.从传入值的地址开始直到第一个'\0'
知识点18:定义指针变量的时候应该同时初始化
int*p = &a;
或者
int*p;
p = &a;
int *p; p = &a;
尽量不要定义后放空如:int *p;
知识点19:指针常用于函数的多值返回 在C++中使用多的是引用
知识点20:数组和字符指针定义字符串的区别
//利用两种方式定义字符串
//1利用数组
char name[] ="it";
name[0] = 'T';//这是可以的,字符串变量
//特点:字符串的字符是可以修改的
//使用场景:字符串的内容要经常发生变化
//2.利用指针
char *name2 ="it";
name[0] = 'T';//这是不可以的,字符串常量
//特点:字符串的内容不可以修改
//使用场景:字符串的内容不需要修改,而且这个字符串经常用到
知识点21:保存在常量区的相同值 占用的时同一块内存
#include <stdio.h>
intmain()
{
char *str1 = "abcd";
char *str2 = "abcd";
printf("str1的地址是%p\n",str1);
printf("str2的地址是%p\n",str2);
return 0;
}
执行的结果是:
str1的地址是0x10373bf66
str2的地址是0x10373bf66
知识点22
:常量区、堆、栈
可编程内存在基本上分为这样的几大部分:静态存储区、堆区和栈区。他们的功能不同,对他们使用方式也就不同。
静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。
栈区:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
堆区:亦称动态内存分配。程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在适当的时候用free或delete释放内存。动态内存的生存期可以由我们决定,如果我们不释放内存,程序将在最后才释放掉动态内存。但是,良好的编程习惯是:如果某动态内存不再使用,需要将其释放掉,否则,我们认为发生了内存泄漏现象。
知识点23:指向函数的指针
void test(int a)
{
printf("%d\n", a);
}
void (*p)(int) = test;//固定写法
//void (*p)();p = test;同上
(*p)(3);//函数调用,也可以直接p()