在写这第一篇不是提问的博客之前,感谢帮助我学习的柳同学。
1、使用printf函数输出%,不需要进行转换说明时,必须写成%%(puts函数测不需要这样,还有就是printf和puts函数在按顺序输出作为实参的字符串时[puts(".......")和printf("......\n")],效果等同,区别在于puts自动输出换行符而printf则需手动输入\n,但是二者在其他应用情况下的不同还存在printf可进行格式设定而puts不可以
int main()
{
int w = 10;
puts("abcdef");
printf("abcdef\n");
printf("%d\n", w);//不可以写成puts("%d",w);
return 0;
}
2、转换说明中的%f默认显示小数点后6位,%d指定以十进制数的形式显示实参,在平常编写代码涉及进制转换时则可以应用这点来编写,还有就是使用修饰符“#”控制前导显示参数,如图所示,若要让其输出八进制前缀0和十六进制前缀0x或是0X则要用#修饰一下
了解到的一点知识:有时候我们直接用%d的类型转换来表示char、int、short等类型,但其实printf这个函数会将int类型等级以下的类型自动转换为int类型,如会自动把char、short转换为int类型,所以输出的依旧是正确的,但也可能出现不可以的情况,所以要了解一下占位符这个问题。
学习c语言的第二天_jayS431的博客-CSDN博客有看这个博客的内容了解到。
这里写出转换规则中长度指示符对应的类型等级%hhd = char、%hd = short、%d = int、%ld = long、%lld = long long。
hh、h、l、ll这几个就是长度指示符。
补充:%c :字符,字母时用,%s:读取字符串时用,%p:读取地址时用
在相应格式输出时遇到的一些小问题(补零,空格,域宽,保留位数等):
%0md和%md:都是右对齐,但%0md是对齐后不足补0,后者是空格,对齐是指字符宽度m所设置的位数从左向右数满足m位后以右为基准,但如果输入的位数>=m,则全部输出,就像0225,若输入225,%04d情况下输出0225,%4d则为 225,(前面是空格)空格开始数到5为4位。
3、在循环语句中要注意符号的书写,尤其是赋值意义的=和等值的==,如图中的if里的条件是i赋值给5,这意味着当满足i<10的循环条件进入循环时,i的值都被5赋值,则永远满足循环条件i<10,按照if语句的实现,每次都打印5.
所以建议下次可以把变量和数值倒过来写的形式避免这样混淆二者使用。eg:5==i
与上面所述相关的,如下代码的判断也特别容易出错:
int main()
{
int num = 4;
if (num = 5)
{
printf("123");
}
return 0;
和上面所述问题类似,都是混淆了=和==的使用,上图结果输出是123,因为if括号里的判断不是是=,是将5赋值给num的意思,并不是形成num是否等于5的判断(num==5),所以代码的逻辑判断则是执行num为5时打印123的操作。
if语句中如果循环表达式有多个(多于1个),记住不要忘了用大括号括起来,还有就是if和else就近配对,所以要养成良好的编写习惯,不要出现逻辑错误。
4、switch语句:
case后面必须是一个整数,或者是结果为整数的表示式,但不能包含任何变量
int org(int x, int y, int z)
{
if (abs(x - y) < z && x + y > z)
{
if (x == y && y == z)
return 0;
else
{
if (x == y || x == z || y == z)
return 1;
else
return 2;
}
}
else
return -1;
}
int main()
{
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
switch(org(a,b,c))//这里为函数返回判断
{
case 0:
printf("Equilateral triangle!\n");
break;
case 1:
printf("Isosceles triangle!\n");
break;
case 2:
printf("Ordinary triangle!\n");
break;
case -1:
printf("Not a triangle!\n");
break;
}
return 0;
}
switch case加范围判断,语法上也要相应的改变_晨洛溪月的博客-CSDN博客_switch case范围判断
并不是每个情况都要写表达式,也可以是多个请况表示同一个输出:如下图
int month = 0;
printf("请输入一个月份:");
scanf("%d", &month);
switch (month)
{
case 1:
case 2:
case 3:
printf("春\n");
break;//不要忘了break,否则在进入case后会一直执行,会输出后面所有的内容
case 4:
case 5:
case 6:
printf("夏\n");
break;
case 7:
case 8:
case 9:
printf("秋\n");
break;
case 10:
case 11:
case 12:
printf("冬\n");
break;
default: //若是自已所列情况都没有(超出处理范围,没有可以匹配的case),
printf("输入错误");//可以加个default来终止(default后也可进一步写相应的说明)
break;
}
switch允许嵌套使用
int main()
{
int n = 1;
int m = 2;
switch (n)
{
case 1:m++;//没有break,一直往下执行
case 2:n++;
case 3:
switch (n)//嵌套使用switch
{
case 1:n++;
case 2:m++; break;
}
case 4:m++;
default:
break;
}
}
5、原来break和continue都是中断循环的作用,但goto在跳出循环时会比较直接,不用一层层的跳出循环,但我们现在可能使用较少,因为我们(小白)写的没那么复杂
break和continue的中断还是有区别的:break是跳出整个循环,continue是跳出本次循环
int main()//结果输出的数字是从1到4
{
int i = 1;
while (i <= 10)
{
if (i == 5)
continue;//continue的作用是终止本次循环中后面的代码,
printf("%d\n", i); //所以当i等于5时,后面的代码不再执行,
i++;
}
return 0;
}
如图,当i++在前面时,i为5时,continue终止了后面printf的执行,于是没有打印5,因为continue是终止本次也就是i==5的那次循环,而5<10仍满足循环条件,循环还是会继续,所以会继续打印直到循环结束。
continue也可以这样用,感觉具有筛选或者说选择的作用:
int main()
{
int ch = 0;
while ((ch = getchar()) != EOF)
{
if (ch < '0' || ch>'9')//只打印在ACSII内字符0到字符9的数字字符
continue;
putchar(ch);
}
return 0;
}
6、%和/,经常被提及且忽略的一个问题,%是取模,且二者都要是整数,然后/表示除法得到的商,若想不舍去结果的小数,可以加个小数位,eg:10/3=3,改为10.0/3或是10/3.0
7、读取数字的最后一位的做法,%10即可,
看到一个反向输出一个四位数的很好的代码,自己完全没想到还可以用这个方式,或者说用循环:感觉小写的好好啊,我自己写的时候只想到了分别输出:让四位数字分别为a=n%10,b=n/10%10; c=n/100%10; d=n/1000; printf("%d%d%d%d",a,b,c,d)来输出。
#include
int main()
{
int a = 0;
scanf("%d", &a);
while (a)
{
printf("%d",a%10);
a = a /10;
}
return 0;
}
还有这个版本;
#include
int main()
{
int n=0;
scanf("%d",&n);
int i=0;
for(i=0;i<4;i++)
{
printf("%d",n%10);
n/=10;
}
return 0;
}
学习过程中被别人的代码给吸引到,这就是简洁干练,还富有逻辑性。
8、getchar():字符输入函数,将输入的第一个字符作为函数的返回值,所以可以用循环读取所有,例如:
int main()
{
int ch,a;
char password[10] = { 0 };
scanf("%s", password);
while ((ch = getchar()) != '\n')//表示一直读取输入的字符直到出现'\n'
{
; //就是读取输入的全部值直到最后\n结尾
}
printf("请确认(Y/N):");
a = getchar(); //
if (a == 'Y')
printf("成功");
else
printf("失败");
return 0;
}
scanf读取数字的规则:C语言,scanf读取数字的规则_Monody_theone的博客-CSDN博客_scanf读取规则
用户输入的内容会保存在输入队列中,
读取%d时,读取输入队列中的数字,直到遇到不是数字的字符(例如空格、小数点)就结束一次读取。
读取%f时,读取输入队列中的内容,直到遇到第二个小数点或其他不是数字的字符。
下一次读取会接着上次读取到的位置继续读取。(在仅读取数字时会忽略空白字符(空格、换行符、水平制表符等)而继续读取下面的内容)
C语言,关于连续使用多个scanf()函数读取字符的事_Monody_theone的博客-CSDN博客_连续使用scanf函数
putchar():字符输出函数,当括号里是表示的是整型数据时,输出的是对应的ASCII的码值。两函数的使用为:ch=getchar() (设置一个变量ch接收getchar内容), putchar(ch) (putchar接收变量ch的输入内容)具体可看如下链接: C语言getchar和putchar函数的用法_3097的博客-CSDN博客_c语言getchar和putchar用法
9、关于计算数据类型长度的问题:
用sizeof函数计算
当计算数组长度时可用如下代码形式:用总的数组大小除以单个元素所占空间大小。
#include
#include
int main()
{
int a[] = { 1,2,3,4,5 };
printf("%d\n", sizeof(a) / sizeof(a[0]));
strlen函数计算字符串长度:不会把'\0'计算在内,因为其为字符串结束标志,不算作字符串内容,例如;char arr1[]='abc'; char arr1[]={'a','b','c','\0'}; printf("%d %d\n",strlen(arr),strlen(arr1));运行后的结果都为3。如果是以这种形式(char arr[]={'a','b'};)来给数组赋值,则并不清楚结束标志在哪,当用printf计算其长度时,为一个随机值,直到'\0'出现才结束计算。
10、关于static关键字修饰:
在修饰局部变量时:可以让他的生命周期更长(用自己的话来说就是当这个变量使用过后仍保留了之前执行过后的数值,可以达到累积作用的效果)
int a = 10;//全局变量
int try()
{
static int a = 10;//a在try函数内初始化为10,并接着自加1,
return a++;
//因为有static的修饰,所以每次进入这个函数后a的值是上次运行过后的值,
//而不会是进入函数而又被初始化为10,如果去掉static则每次进入函数a的
//值都为10,再进行自加,结果只是11
}
在修饰全局变量时:改变了变量的作用域(让静态的全局变量只能在自己所在的源文件内部使用,出了源文件则没法使用)
//在add.c中:
int a=10;//全局变量
//在test.c中:
printf("%d\n", a);//若要引用add.c中的a的值,则改为
extern int a;
printf("%d/n", a);//这样可以正常使用a的值,
//但如果用了static修饰全局变量:如下所示,则不能引用a的值
//在add.c中:
static int a=10;//全局变量
//在test.c中:
extern int a;
printf("%d\n", a);
在修饰函数时:也会达到和修饰全局变量一样的效果,如果在源文件要引用别的文件里定义的函数,则直接在源文件里用extern声明即可,然后就可以正常引用,但如果该文件里的函数定义用了static修饰,则不能被别的文件引用了,效果同修饰全局变量相同,但修饰函数的本质是,改变了函数的链接属性,由原来的外部链接属性变成内部链接属性。(不可以被外部引用了)
11、常量分为如下几种:
字面常量,const修饰得常量,#define定义得标识符常量,枚举常量
//在程序里面,为基本数据类型赋值的结果值被称之为字面常量,
//例如,int a = 10;这个10被称之为字面常量
1; //字面常量
'a'; //字面常量
const int a = 1; //const修饰的常变量,被const修饰的变量具有常属性,
//具体表现如下:
const int n = 10;
int arr[n] = { 0 }; //不可以用n表示,因为n仍为变量
n = 11;//同样也不可更改n的值,因为n是被const修饰,具有常属性
#define n 10 //#define定义的标识符常量
int arr[n] = { 0 }; //可以用n来表示(const修饰n的话则不能)
//补充:可用#undef取消定义:undef n (const定义变量后则不能改变)
//枚举常量:用关键字enum,如果枚举没有初始化则从第一个名称开始其值为0,
//第二个为1,以此类推,但也可以给名称赋一个特殊值,
enum color { red,green=5,blue};//red,green等为枚举常量
//如上得blue=6,(默认请况下每个名称都会比前一个名称大一)
//red=0
12、结构体和访问运算符(.运算符和->运算符)
#include
#include
struct student {
char name[10];
int height;
float weight;
};
int main()
{
struct student xyz;
struct student* p = &xyz;
strcpy(xyz.name, "san");//也可以这样初始化:
xyz.height = 167; //struct student xyz={"san",167,110};
xyz.weight = 110; //但记得要对应结构体里定义的成员顺序,未被初始化的值则为0
printf("%s\n", xyz.name);
printf("%s %s\n", p->name,(*p).name);//p->name等价于(*p).name
//上面代码的表现形式不同,但打印的结果相同,都为san
return 0;
}
13、只要是整数,内存中存储的都是二进制的补码,所以在取反时若要打印输出取反后的值要注意形式转换,例如:int a=0;其为4个字节,32位二进制数,所以取反后应该为1111......,但存储为补码,所以其被存为10....01(补码形式),取反后打印为-1。类似地,取反也可以运用于循环的判断条件里,例如:
int main()
{
int a, b;
while (~scanf("%d %d", &a, &b))//取反运算,这里的意思是将scanf的返回值取反运算
if (a >= b) //while循环里只有当条件为假(0)时才跳出循环
printf("a"); //因为scanf返回值为非0(为真)所以该循环可以一直运行
else
printf("b");
return 0;
我们可以稍微了解一下scanf的返回值,我的大概理解就是,根据所要输入的值的个数,对有效输入值进行判断,则若有两个值需要输入,输入有效数值为2(正确输入了两个变量的意思)时,返回值为2,有效数值为1,则返回值为1。
根据储存形式为补码的条件,不管我们怎样输入它在二进制里的补码表示后判断都为真(非0),(存在两种情况,在程序里以补码储存的二进制数取反操作后为正数或为负数,但不管是正数负数,只要不为0则为真不会跳出循环,所以一直都可以输入,然而即使是不输入,循环也可以继续,因为不输入则scanf返回值为0,取反运算后为负数,为非0。)
相比与上面的取反运算,还是不等于EOF比较好理解,就是scanf的返回值只要有被读取(正确的输入),它都是不等于-1的返回值,所以可以一直输入(循环),如图所示:
int main()
{
int a, b;
while (scanf("%d %d", &a, &b)!=EOF)//这个判断形式等同于上面的取反运算
if (a >= b) //在这个代码中的实现效果相同,都是可以
printf("a"); //一直输入两个数a,b,并输出较大的那个值
else
printf("b");
return 0;
关于scanf的返回值可通过这篇内容了解一下:~scanf的意思、作用_SiriusSun_的博客-CSDN博客_~scanf
零零碎碎的:
1、typedef 关键字可用来为一个已有类型取一个名字,例如:typedef int inter;则后面写代码时 int a ;等价于 inter a; 都为创建了一个整型变量a的意思。
2、extern 关键字用于声明外部符号
3、int定义的变量是有符号的,每个被创建的局部变量都省略了auto(自动变量)
4、printf的返回值是输出的字符数,\n也算一个字符输出,汉字的话,一个汉字算2个字符
5、一些转义字符:\ddd 表示1到3位八进制的数字 \xdd表示2个十六进制数字 \t 水平制表符等,其中当用' '单引号引起表示时,代表该进制数在ASCII里对应的字符,例如:char a='\072',则a表示的是八进制数72在表里对应的字符。详细可通过该链接了解http://t.csdn.cn/J2kKo