C基础学习(认真看就能学会C语言)

1、书接上回,运算符的使用

1.1 sizeof运算符

	sizeof运算符用来计算数据类型的占用内存空间的大小,单位为字节。
	
格式:
	sizeof(数据类型名);
	
	64位系统:返回long int类型,使用格式化字符-》%ld
	
	32位系统:返回int类型,使用格式化字符-》%d
#include <stdio.h>

int main(int argc, const char *argv[])
{
//#define  X86_64
#ifdef  X86_64
 printf("unsigned char size = %ld\n", sizeof(unsigned char));
 printf("unsigned short size = %ld\n", sizeof(unsigned short));
 printf("unsigned int size = %ld\n", sizeof(unsigned int));
 printf("unsigned long size = %ld\n", sizeof(unsigned long));
 printf("unsigned long long size = %ld\n", sizeof(unsigned long long));
 printf("float size = %ld\n", sizeof(float));
 printf("double size = %ld\n", sizeof(double));
 printf("long double size = %ld\n", sizeof(long double));
#else 
 printf("unsigned char size = %d\n", sizeof(unsigned char));
 printf("unsigned short size = %d\n", sizeof(unsigned short));
 printf("unsigned int size = %d\n", sizeof(unsigned int));
 printf("unsigned long size = %d\n", sizeof(unsigned long));
 printf("unsigned long long size = %d\n", sizeof(unsigned long long));
 printf("float size = %d\n", sizeof(float));
 printf("double size = %d\n", sizeof(double));
 printf("long double size = %d\n", sizeof(long double));

#endif
 return 0;
}

image-20230407094054767

image-20230407094128062

1.2 逗号运算符

格式:
	(表达式1, 表达式2, 表达式3,....);
	最后一个表达式的结果被返回。
#include <stdio.h>

int main(int argc, const char *argv[])
{
 int a = 10;
 int b = 20;
 int c = 30;

 int d = (a++, ++b, --c); // a = 11 b = 21 c = 29 d = 29
 // 逗号运算符里边的所有的表达式都被执行了,
 // 只是最后一个表达式的结果被返回。
 // 在使用逗号运算符时,必须在最外边添加(),不可以省略

 printf("a = %d, b = %d, c = %d, d = %d\n",
   a, b, c, d);

 // int f = ++a,++b; // 错误
 return 0;
}

1.3 运算符的优先级

运算符优先级从高到低: 单算移关与,异或逻条赋,逗号
	单 :+(正数) -(负数) ++ -- ~(按位取反)  !(非)
	算 : + - * / %
	移 : << >>
	关 : > < >= <= != ==
	与 : &(按位与)
	异 : ^(按位异或)
	或 :|(按位或)
	逻 :&& || 
	条 : ?:
	赋 : = += -= *= /= %= &= |= ^= <<= >>=
	逗号 : ,
	
同级运算符结合的问题:
	单条赋:从右到左结合, 
		比如:a = b = 1; 从右到左结合,先把1赋值给b,再把b赋值给a
	剩余的都是从左到右结合
		比如:a && b && c;  从左到右结合,先进行a && b,结果在&&c
可以参考《运算符优先级.docx》文档,已经上传有道云笔记中。

2、常用的输入输出函数

学习任何一个函数,都要先掌握函数的功能,参数,返回值。
系统提供的函数都有可以使用man查看对应的帮助手册。
man man ---> 查看man的帮助手册
  	   1   可执行程序或 shell 命令
       2   系统调用(内核提供的函数)
       3   库调用(程序库中的函数)
       4   特殊文件(通常位于 /dev)
       5   文件格式和规范,如 /etc/passwd
       6   游戏
       7   杂项(包括宏包和规范,如 man(7),groff(7))
       8   系统管理命令(通常只针对 root 用户)
       9   内核例程 [非标准

man 3 库函数的名字,比如 man 3 putchar

2.1 putchar/getchar函数

2.1.1 putchar函数

#include <stdio.h>
int putchar(int c);
 |		|	  |---> 函数的形参,调用函数时需要传递一个实参。
 |		|----> 函数的名字
 |---> 函数返回值的类型,可以使用对应类型的变量接收函数的返回值
  
功能:输出一个字符到终端
参数:
	@ c : 要输出的字符
		1> 可以是一个字符常量
		2> 可以是一个字符类型的变量
		3> 可以是一个字符对应的ASCII码值
		4> 可以是一个整数,输出整数对应ASCII码表中的字符,
			如果超过ascii码表的最大值,输出一个乱码。
		5> 可以是一个经过运算的表达式,表达式的结果是一个整数。
返回值:
	成功返回写到终端上的字符的对应的整数值,
	失败返回错误码EOF(-1);
	
#include <stdio.h>
int main(int argc, const char *argv[])
{
 // 1. 可以传递字符常量 
 int retVal = putchar('A');
 // 有可能失败,因此需要进行出错处理
 if (retVal == -1)
 {
  printf("输出字符失败\n");
  return -1;
 }
 else
 {
  printf("输出字符成功:%c --- %d\n", retVal, retVal);
 }
 
 // 2. 可以传递字符类型的变量
 char ch = 'a';
 putchar(ch);
 putchar('\n');  // 输出一个换行符 

 // 3. 可以传递一个整数值
 putchar(97);   // a 的ascii码值为97
 putchar(10);   // /n 的ascii码值为10
 

 // 4. 可以是一个结果为整型的表达式
 putchar('A'+33); 
 putchar(5+5);

 return 0;
}

2.2.2 getchar函数

#include <stdio.h>
int getchar(void);
功能:从终端获取一个字符
参数:
	无
返回值:
	成功:返回接收字符对应的ascii码值
	失败:返回错误码EOF(-1)

#include <stdio.h>
int main(int argc, const char *argv[])
{
	char a, b, c;
	// 使用getchar连续接收3个字符
	a = getchar();
	b = getchar();
	c = getchar();
	
	printf("a = %c, b = %c, c = %c\n", a, b, c);

	return 0;
}

image-20230407134054886

image-20230407134200192

#include <stdio.h>
int main(int argc, const char *argv[])
{
 char a, b, c;
 // 使用getchar连续接收3个字符
 a = getchar();
 getchar(); // 处理垃圾字符,只能处理一个垃圾字符
 b = getchar();
 getchar();
 c = getchar();
 
 printf("a = %c, b = %c, c = %c\n", a, b, c);

 return 0;
}

image-20230407134359481

2.2 puts/gets函数

2.2.1 puts函数

#include <stdio.h>
int puts(const char *s);
功能:向终端输出一个字符串
参数:
	@ s : 输出字符串的首地址
		1> 可以是字符串常量
		2> 可以是字符数组的名字
		3> 可以是指向一个字符串的字符指针
返回值:
	成功:返回一个非负的整数, 发送成功的字符串的个数(字符串长度+1)
	失败:返回错误码EOF(-1)

注:puts函数在发送字符完成之后,会自动补发一个'\n'换行符
#include <stdio.h>

int main(int argc, const char *argv[])
{
 // c语言的字符串的结尾为'\0',输出字符串时遇到'\0'停止输出

 // 1. 可以传递一个字符串常量
 // 字符串发生结束之后自动补发一个'\n'字符
 int retVal = puts("hello world!!!");
 // EOF系统提供的错误码,本质就是一个宏定义 
 // #define  EOF  -1
 if ( retVal != EOF)
 {
  printf("发生字符串成功:%d\n", retVal);
 }
 else
 {
  printf("发生字符串失败\n");
  return EOF;
 }

 puts("");  // 发生一个换行符

 // 2. 可以传递一个字符数组
 // 数组名就表示字符数组的首地址
 char name[20] = "zhangsan";
 puts(name);

 // 3. 可以传递一个执行字符串的字符指针
 char *str_p = "nihao"; // 字符指针指向一个字符串串常量
 // str_p中存放的就是字符串常量的首地址
 puts(str_p);

 
 // 输出字符串时遇到'\0'结束
 puts("hello\0world");  // 输出hello
 return 0;
}

2.2.2 gets函数

#include <stdio.h>

char *gets(char *s);
功能:从标准输入获取一个字符串
参数:
	@ s : 将接收的字符串存到哪个地址中
返回值:
	成功:返回s,及接收字符串的缓冲区的首地址
	失败:返回NULL
	
注:gets可以接收中断所有输入的字符包括空格,当输入回车时,输入结束,
	最终会在字符串的结尾补一个'\0'.
	即使输入的字符串的长度大于接收字符串缓冲区的长度,也可以接收,
	并不会进行越界的检查,但你在此打印字符串时,就会越界访问内存空间,
	就会出现段错误。
#include <stdio.h>

int main(int argc, const char *argv[])
{
 // 将接收的字符串存放一个字符数组的缓冲区
 char buffer[20];   //缓冲区最多接收19个字符,最后存一个'\0'

 printf("please input a string, char number < 20 > ");

 // 从终端获取字符串,有多少接收多少,并不会进行越界的检查
 // 如果越界之后,访问非法空间时,执行程序可能会报段错误
 // 一旦出现段错误一般都是访问了非法的内存空间。
 // 在实际的开发中一般解bug遇到最多的错误就是段错误,
 // 这种错误在程序编译时不会报错,执行时才会报错。
 char *retVal = gets(buffer);
 if (retVal == NULL)
 {
  puts("从标准输入获取字符串失败");
  return -1;
 }

 puts(buffer);

 return 0;
}

2.3 printf/scanf函数

2.3.1 printf函数

#include <stdio.h>

int printf(const char *format, ...);

功能:向终端输出一个格式化字符串
参数:
	@ format : 参数控制格式的字符串
	@ ... : 可变参数, 可变参数有几个由format中的格式字符决定,
		可变参数会依次替换format中的格式化占位符,
		要求参数的类型和格式化字符要一一对应。
返回值:
	成功返回正数,失败返回负数

格式化字符:

image-20230407150235730

image-20230407150255315

#include <stdio.h>

int main(int argc, const char *argv[])
{
 int x = 0x12345678;
 printf("Dct x = %d\n", x);
 printf("Dct x = %u\n", x);
 printf("Oct x = %o\n", x);
 printf("Oct x = %#o\n", x);
 printf("Hex x = %x\n", x);
 printf("Hex x = %#x\n", x);

 printf("char c = %c\n", 'A');
 printf("string str = %s\n", "hello world!");

 double Pi = 3.141500;
 printf("Pi = %lf\n", Pi); // 默认输出小数点后6位
 printf("Pi = %le\n", Pi); 

 printf("Pi= %g\n", Pi);  // 3.1415
  
 printf("Pi = %10lf\n", Pi);  
 // 占10位宽度,默认右对齐, 不足补空格,
 // 超过10位宽度原样输出
 
 printf("Pi = %010lf\n", Pi); // 
 // 占10位宽度, 默认右对齐,不足补0,
 // 超过10位宽度原样输出
 
 printf("Pi = %10.3lf\n", Pi);
 // 浮点数,.3保留小数的后三位,不足3位补0
 printf("Pi = %-10.5lf\n", Pi);
 // - : 左对齐
 
 return 0;
}

2.3.2 scanf函数

#include <stdio.h>

int scanf(const char *format, ...);
功能:从终端接收数据
参数:
	@ format : 格式控制字符串
	@ ... : 可变参数,需要提供的是变量的地址,
		只有提供的是地址时,才可以将通过终端读取的数据存到变量对应的空间中。
返回值:
	成功返回正数,失败返回负数。

image-20230407154328201

image-20230407154346962

#include <stdio.h>

int main(int argc, const char *argv[])
{
 char c;
 // 变量名前加&符号,表示对变量取地址
 printf("please input char type data > ");
 scanf("%c", &c);
 printf("c = %c\n", c);

 short s;
 printf("please input short type data > ");
 scanf("%hd", &s);
 printf("s = %hd\n", s);


 int i;
 printf("please input int type data > ");
 scanf("%d", &i);
 printf("i = %d\n", i);


 float f;
 printf("please input float type data > ");
 scanf("%e", &f);
 printf("f = %e\n", f);

 char name[20];
 printf("please input string type data > ");
 scanf("%s", name);
 printf("name = %s\n", name);
 return 0;
}

#include <stdio.h>

int main(int argc, const char *argv[])
{
#if  0
 // 1. 可以同时接收多个参数
 int a, b;
 printf("please input two number(int,int) > ");
 // 当输入多个参数时,多个参数的输入可以以空格,tab键,回车分隔,
 // 系统会自动的吃掉空格,tab键和回车符。
 scanf("%d%d", &a, &b);
 printf("a = %d, b = %d\n", a, b);
#endif 
#if  0
 // 2. scanf格式化字符串中除了格式化字符以外,
 // 还有很多其他的字符,需要按照格式化字符串原样进行输入,
 // 否则结果出错
 int year,mouth,day;
 printf("please input year, mouth, day > ");
 scanf("year=%d,mouth=%d,day=%d", &year,&mouth,&day);
 printf("%d:%d:%d\n", year,mouth,day);
#endif 
#if 0
 // 3. scanf默认不可以获取带有空格的字符串,
 // 默认遇到一个空格之后,输入结束
 char name[20];
 // printf("please input your name > ");
 // scanf("%s", name);
 // printf("name = %s\n", name);
 
 // 方式1:使用gets可以接收带空格的字符串
 // printf("please input your name > ");
 // gets(name);
 // printf("name = %s\n", name);
 
 // 方式2 : 使用[^\n]符号,除了\n以外的所有字符都接收
 printf("please input your name > ");
 scanf("%[^\n]s", name);
 printf("name = %s\n", name);
#endif 

#if 0
 // 以下几种情况,当输入数据之后,系统无法自动吃掉
 // 空格,tab键,回车符,scanf函数处于阻塞无法退出,
 // 当按下任意一个字符之后,在回车就会退出。
 // 因此在使用scanf函数时,格式化字符串的结果不要有
 // 空格, \t \n \r
 int a, b, c;
 //scanf("%d\n", &a);
 scanf("%d\t", &b);
 // scanf("%d ", &c);
#endif

#if 0 
 // 将\n \t \r, 空格写到格式化字符的前边,
 // 系统会自动的吃掉\n,\t,\r,空格。
 int a, b, c;
 //scanf("\n%d", &a);
 scanf("\t%d", &b);
 // scanf(" %d", &c);
#endif 
    return 0;
}

image-20230407160036020

scanf接收字符时,处理垃圾字符的问题。

#include <stdio.h>

int main(int argc, const char *argv[])
{
 int a, b;
 char oper;
 printf("请输入一个表达式(l # r) > ");
 // 输入三个参数时,三个参数以空格分割,空格也是一个字符
 // 被%c接收之后,赋值给oper,对于程序来说,空格就是一个
 // 垃圾字符,需要处理垃圾字符
 // scanf("%d%c%d", &a, &oper, &b);
 
 // 方式1:使用%*c 吃掉一个垃圾字符
#if 0
 // scanf("%d%*c%c%*c%d", &a, &oper, &b);
 scanf("%d", &a);
 scanf("%*c");  // 吃掉垃圾字符
 scanf("%c", &oper);
 scanf("%*c");
 scanf("%d", &b);
#endif 
 // 方式2:使用getchar()函数接收一个垃圾字符
 scanf("%d", &a);
 getchar();   // 吃掉垃圾字符
 scanf("%c", &oper);
 getchar();
 scanf("%d", &b);
 
 // 在接收字符类型的变量时需要思考是否需要吃掉垃圾字符

 if (oper == '+')
 {
  printf("a + b = %d\n", a + b);
 }

 if (oper == '-')
 {
  printf("a - b = %d\n", a - b); 
 }
 return 0;
}

3、if...else分支语句

3.1 语法格式

1. if
	if (表达式)
	{
		C语句块;
	}
	
	执行过程:“表达式”成立,执行“C语句块”,
		“表达式”不成立,跳过“C语句块”,向下继续执行

2. if...else...
	if (表达式)
	{
		C语句块1;
	}
	else 
	{
		C语句块2;
	}
	
	执行过程:“表达式”成立,执行“C语句块1”,
		“表达式”不成立,执行“C语句块2”,执行完成之后在向下执行

3. if...else if ... else...
	if (表达式1)
	{
		C语句块1;
	}
	else if (表达式2)
	{
		C语句块2;
	}
	else if (表达式3)
	{
		C语句块3;
	}
	...此处省略很多else if...
	
	else		/* else 分支可以省略不写*/
	{
		C语句块n;
	}
	
	执行过程:判断表达式1是否成立,如果成立执行C语句块1,
		执行完C语句块1之后,后边的所有的判断都不在进行判断,即使成立。
		如果表达式1不成立,则判断表达式2,如果成立执行C语句块2,
		执行完C语句块2之后,后边的所有的判断都不在进行判断,即使成立。
		其他的都是一样的依次类推。
		只有前边所有的表达式都不成立时,才会执行else分支对应的C语句块n.
		
	表达式:只要是一个可以表示真假的表达式都可以。
		一般为逻辑表达式,判断表达式

3.2 案例

1. 从终端输入一个字符,判断字符为大写字符,小写字符,数字。
#include <stdio.h>

int main(int argc, const char *argv[])
{
 char ch;
 printf("please input a char > ");
 scanf("%c", &ch);
 
 if (ch >= 'a' && ch <= 'z')
 {
  printf("%c是一个小写字符\n", ch);
 }
 else if (ch >= 'A' && ch <= 'Z')
 {
  printf("%c是一个大写字符\n", ch); 
 }
 else if (ch >= '0' && ch <= '9')
 {
  printf("%c是一个数字\n", ch); 
 }
 else
 {
  printf("%c既不是大小写字符,也不是数字\n",ch);
 }
 return 0;
}
-------------------------------------
  #include <stdio.h>

int main(int argc, const char *argv[])
{
 char ch;
 printf("please input a char > ");
 scanf("%c", &ch);
 if ((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9'))
 {
  printf("%c既不是大小写字符,也不是数字\n",ch);
  return -1;
 }

 
 if (ch >= 'a' && ch <= 'z')
 {
  printf("%c是一个小写字符\n", ch);
 }
 else if (ch >= 'A' && ch <= 'Z')
 {
  printf("%c是一个大写字符\n", ch); 
 }
 else
 {
  printf("%c是一个数字\n", ch); 
 }
 return 0;
}
 
    
从终端输入薪资,选则不同的交通工具。
#include <stdio.h>
int main(int argc, const char *argv[])
{
 int salary;
 printf("请输入你的薪资 > ");
 scanf("%d", &salary);


 if (salary < 0)
 {
  printf("输入的薪资不合理请重新输入\n");
  return -1;
 }

 if (salary <= 10000)
 {
  printf("地铁\n");
 }
 else if (salary <= 30000)
 {
  printf("出租\n");
 }
 else if (salary <= 50000)
 {
  printf("自驾\n");
 }
 else if (salary <= 100000)
 {
  printf("专职司机\n");
 }
 else
 {
  printf("自由选择\n");
 }


 return 0;
}

练习题1:
    在终端输入一个整数,用来表示学生的成绩
    输出学生成绩对应的等级
        [90,100]	A
        [80, 90)	B
        [70, 80)	C
        [60, 70)	D
        [0,60)		E
#include <stdio.h>
int main(int argc, const char *argv[])
{
 int score;
 printf("请输入成绩 > ");
 scanf("%d", &score);
 if ( score < 0 || score > 100)
 {
  printf("输入成绩不合理请重新输入\n");
  return -1;
 }
 
 if (score >= 90 && score <=100)
 {
  printf("等级A\n");
 }
 else if (score >= 80 && score < 90)
 {
  printf("等级B\n");
 }
 else if (score >= 70 && score < 80)
 {
  printf("等级C\n");
 }
 else if (score >= 60 && score < 70)
 {
  printf("等级D\n");
 }
 else
 {
  printf("等级E\n");
 }

 if (score >= 90 /*&& score <=100*/)
 {
  printf("等级A\n");
 }
 else if (score >= 80 /* && score < 90 */)
 {
  printf("等级B\n");
 }
 else if (score >= 70 /* && score < 80 */ )
 {
  printf("等级C\n");
 }
 else if (score >= 60 /* && score < 70 */)
 {
  printf("等级D\n");
 }
 else
 {
  printf("等级E\n");
 }

 // 如果if...else分支中只有1条c语句,可以省略{}
 if (score >= 90)
  printf("等级A\n");
 else if (score >= 80 && score < 90)
  printf("等级B\n");
 else if (score >= 70 && score < 80)
  printf("等级C\n");
 else if (score >= 60 && score < 70)
  printf("等级D\n");
 else
  printf("等级E\n");


 return 0;
}
       
练习题2:
 在终端输入一个整数,用来表示年份,输出这一年是平年还是闰年
 闰年:能被4整除且不能被100整除,或者能被400整除

#include <stdio.h>
int main(int argc, const char *argv[])
{
 int year;
 printf("请输入年份 > ");
 scanf("%d", &year);

 if (year <= 0)
 {
  printf("输入的年份不合理\n");
  return -1;
 }

 if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
 {
  printf("%d年是闰年\n", year);
 }
 else {
  printf("%d年是平年\n", year); 
 }


 return 0;
}

练习题3:
 在终端输入三个整数,分别表示三角形的三边长
 输出能否构成三角形
 如果能构成三角形,再输出能构成什么类型的三角形:等腰、等边、直角、普通。
 
 使用if嵌套。

#include <stdio.h>
int main(int argc, const char *argv[])
{
 int a, b, c;
 puts("请输入三角形的三个边长(a,b,c) > ");
 scanf("%d%d%d", &a, &b, &c);

 if (a <= 0 || b <= 0 || c <= 0)
 {
  puts("输入的边长至少有一个小于等于0");
  return -1;
 }

 if (a + b > c && a + c > b && b + c > a)
 {
  puts("可以构成三角形");
  if (a == b && b == c /* && a == c */ )
  {
   puts("等边三角形");
  }
  else if (a == b || b == c || a == c)
  {
   puts("等腰三角形");
  }
  else if (a*a + b*b == c*c || a*a + c*c == b*b || b*b + c*c == a*a)
  {
   puts("直角三角形");
  }
  else 
  {
   puts("普通三角形");
   
  }
 }
 else
 {
  puts("不可以构成三角形");
 }
 return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值