C语言数据类型和变量

目录

 数据类型

整型

浮点型、布尔型

字符型

变量

 变量的分类

变量的存储位置

sizeof关键字

算数操作符

+、-、*、/、%

赋值操作符=(从右往左)

单目操作符++、--

强制类型转换

printf()制定占位符的输出格式

scanf


 数据类型

内置类型就是平时日常生活中用的多的类型,比如数学中的整数、小数,英语中的字母。

一个或多个内置类型放在一起,就构成了自定义类型。举个例子,一个人的姓名ZhangSan,就是自定义类型中的数组(多个字符组成的集合)。自定义类型也可以嵌套(自定义类型跟内置类型组成一个新的自定义类型),以后再讲。

整型

整型有很多,这里先介绍int。int是整形,就是整数,具体点呢就是有符号的整数,它的全称是signed int。为了简便,signed可写可不写

#include<stdio.h>
int main()
{
	int a = -5;
	printf("%d\n", a);
	
	signed int b = -99;
	printf("%d\n", b);
	return 0;
}

运行结果:

int是有符号的,可以表示正数、负数、0,那有没有无符号的呢?答案是有,unsigned int

#include<stdio.h>
int main()
{
	unsigned int a = -5;
	printf("%u\n", a);    //打印 int 用 %d,打印 unsigned int 要用 %u
	return 0;
}

运行结果:

我把-5存在了unsigned int类型中,结果却没有打印-5,而是一个很大的数字。至于为啥是这个数,要学了原码、反码、补码才能给你解释。

如果你把上面代码中的%u换成%d,结果会打印出-5。至于为啥,enmm,就 不 告 诉 你~~

算了直接看下面这段代码:

#include<stdio.h>
int main()
{
	int a = -5;
	printf("a以d的形式打印:%d\n", a);
	printf("a以u的形式打印:%u\n", a);
	
	unsigned int b = -5;
	printf("b以d的形式打印:%d\n", b);
	printf("a以u的形式打印:%u\n", b);
	return 0;
}

运行结果:

哎嘿!结果竟然出奇的一致!可是我明明一个用int类型储存-5、一个用unsigned int类型储存-5啊!心机之蛙一直摸你肚子——这两个是同一个东西!在底层,变量是以二进制形式储存在计算机中,代码中的a和b在内存中储存的是同一个二进制序列!%d与%u只是将同一个二进制序列以不同的形式打印出来!可恶,绕了半天结果告诉我int跟unsigned int存的是“同一个东西”。

我对这两者之间的区别理解的并不是很深,只能告诉你一个是有符号,一个无符号,int的取值范围是-2^31 ~ 2^31 - 1,unsigned int的取值范围是0~2^31。如果你有更深刻的见解,欢迎在评论区交流!

对了,取值范围不用刻意去记,直接用代码就行,换成全大写的int再加上下划线再加上全大写的max就表示int的最大值,不过要包含下头文件limits.h

#include<stdio.h>
#include <limits.h>
int main()
{
	int a = INT_MAX;
	unsigned int b = UINT_MAX;
	printf("%d\n", a);    //2147483647
	printf("%u\n", b);    //4294967295
	return 0;
}

好了,接下来我们该跟整型家族暧昧一下了。打印下面各种整型的占位符(%d还是%ld啊)无需刻意去记,不知道的就百度一下就行了。

短整型整型长整型长长整型(C99引入)
short [int]intlong [int]long long [int]
[signed] short [int][signed] int[signed] long [int][signed] long long [int]
unsigned short [int]unsigned intunsigned long [int]unsigned long long [int]

哇!这么多的吗?实际上用的基本上都是int,打比赛或者刷题数据可能会溢出,换成long long就差不多了,别的类型用的不多。上面的表格中[ ]表示里面的东西可写可不写。比如long [int],可以写成long,也可以写成long int,这两者代表的是一个意思。上面四种,前面没加unsigned的,都是有符号整型,加了unsigned的,都是无符号整型。至于这四者之间的区别,上节已经讲过了,表中从左往右能够储存的数据越来越大,比如short存不下20亿,int就行。

#include<stdio.h>
int main()
{
	short a = 2000000000;
	printf("%d\n", a);
	
	int b = 2000000000;
	printf("%d\n", b);
	return 0;
}

运行结果:

浮点型、布尔型

floatdoublelong double

浮点型不象整型那个繁多,没有unsigned float、unsigned double等。

注:打印浮点型别错用了占位符

#include<stdio.h>
int main()
{
	float b = 3.14;
	printf("%d\n", b);
    printf("%f\n", b);
	return 0;
}

运行结果:

%d是打印整数的,我原本以为用%d打印小数只会保留小数的整数部分,结果却不是的,后面章节会讲为啥是这样。

布尔型只有两种状态:非0表示真true, 0表示假false

通过监视窗口我们就能看出,a跟b都是非0,所以是true,c是0,对应false。细心的通知发现我在前面多包涵了stdbool.h的头文件,bool类型是在C99时引入的,专门表示真假,要用到bool类型就要包含一下头文件哈。

监视是啥?我怎么打开这个东东?在文章最后有讲解。

下面介绍一个简单的语句 -- if( )

if语句就是:括号内是判断条件,判断条件为真,就会输出紧接着的下一个语句,如果有多条语句要输出,就用花括号{ }括起来,当然只有一条语句要输出 也可以用花括号(如第二个if语句)。

#include<stdio.h>
#include<stdbool.h>
int main()
{
	bool a = true;
	if(a)
		printf("C语言是世界上最好的语言!.cpp\n");
		
	bool b = false;
	if(b)
	{
    	printf("C++是世界上最好的语言!.py\n");
	}

	bool c = true;
	if(c)
	{
		printf("C跟C++都是世界上最好的语言!\n");
		printf("代码和我总有一个是能跑的!\n");
	}
	return 0;
}

运行结果:

第一个if语句中a是真,就会执行下面紧接着的printf;第二个if中b是假,就不执行,所以只会打印第一个printf里的内容。

新手我建议统一用花括号{ }。比如看下面的代码:

#include<stdio.h>
#include<stdbool.h>
int main()
{
	bool a = false;
	if(a)
		printf("C语言是世界上最好的语言!.cpp\n");
    	printf("C++是世界上最好的语言!.py\n");

	return 0;
}

运行结果:

明明if括号里的判断条件是假,为什么还会有输出呢?那是因为if只管一条语句。

字符型

char[signed] charunsigned char

字符型记住要用单引号。下面这段代码我想创建啊一个char类型变量储存字符a,可是我用的是双引号,导致我打印变量c时啥都没有输出。

变量

C语言中把经常变化的值称为变量,不变的值称为常量。变量创建的语法形式是这样的:

data_type name;
   |        |
数据类型   变量名

 变量在创建的时候就给⼀个初始值,就叫初始化。如下:

int age = 18;
char ch = 'w';
double weight = 48.5;
unsigned int height = 100;

 变量的分类

  • 全局变量。全局变量的使用范围更广,整个⼯程中想使用,都是有办法使⽤的。
  • 局部变量。局部变量的使用范围是比较局限,只能在自己所在的局部范围内使用的。
#include<stdio.h>

int a = 100;	//全局变量 
int main()
{
	int b = 10;	//局部变量 
	printf("a: %d, b: %d\n", a, b); //全局变量在局部可以使用   
	return 0''
} 

 但下面这段代码就有问题,变量c是在if语句内创建的,却在语句外使用,会直接编译错误

全局变量跟局部变量名字相同时,优先使用局部变量

但是不能在同一个作用域下创建两个名字相同的变量,会直接报错

变量的存储位置

其实内存区域的划分会更加细致,以后在操作系统的相关知识的时候会介绍。


sizeof关键字

这家伙是用来计算数据所占内存的大小,单位是字节Byte,简称B(大写字母B)。(还有个单位是比特bit,简称b(小写字母b)。1字节=8比特,这两种不要混淆了)。sizeof的用法,看代码:

#include<stdio.h>
int main()
{
	int a = 10;
	float b = 3.14;
	double b1 = 3.52;
	char c = 'a';

	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(b));
	printf("%d\n", sizeof(b1));
	printf("%d\n", sizeof(c));
	return 0;
}

运行结果:

也就是说,a跟b分别占了4个字节,b1占了8个字节,c占1个字节

上面的代码也可以这样写,括号里面放数据类型,运行结果是一样的

#include<stdio.h>
int main()
{
	printf("%d\n", sizeof(int));
	printf("%d\n", sizeof(float));
	printf("%d\n", sizeof(double));
	printf("%d\n", sizeof(char));
	return 0;
}

 再奇葩一点,我甚至可以放一个式子!不过这种情况很少遇见,只需了解。

#include<stdio.h>
int main()
{
	int a = 10;
	char c = '1';
	long long d = 99;
	printf("%d\n", sizeof (a + c));    // 4
	printf("%d\n", sizeof (a + d));    // 8
	printf("%d\n", sizeof (c + d));    // 8
	printf("%d\n", sizeof (10 + 11));  // 4
	printf("%d\n", sizeof (a = 22));   // 4
	
	printf("%d\n", a);                 // 10
	return 0;
}

方便起见,我把对应的运行结果用注释写上了。

sizeof( )计算式子的结果取决于占内存空间最大的那个变量(谁最大谁有理)。举个例子,sizeof(a+c)中,a是int类型 占4个字节,c是char类型 占1个字节,占空间最大的是a,所以输出4;sizeof (a + d))中,a占4字节,d占8字节,占空间最大的是d,所以输出8。

最后一行呢?为什么输出10?我在上一行明明写了a=22啊(这条语句意思是把22赋值给a),因为sizeof后面的表达式是不参与计算的,sizeof只计算你占内存多大,压根不管你里面的式子。

上面的代码我都是直接打印结果,我能不能sizeof计算的结果保存在一个变量中呢?要用什么类型的变量储存呢?int吗?int有负数,变量占的内存能为负数吗?那是不是就要用unsigned int呢?

下面这段是详细的解释,你可以直接看黑体字部分

sizeof 运算符的返回值,C语⾔只规定是⽆符号整数,并没有规定具体的类型,⽽是留给系统⾃⼰去决定,sizeof 到底返回什么类型。不同的系统中,返回值的类型有可能是unsigned int ,也有可能是unsigned long ,甚⾄是unsigned long long ,对应的printf() 占位符分别是%u 、%lu 和%llu。这样不利于程序的可移植性。C语⾔提供了⼀个解决⽅法,创造了⼀个类型别名size_t ,⽤来统⼀表示sizeof 的返回值类型。对应当前系统的sizeof 的返回值类型,可能是unsigned int ,也可能是
unsigned long long 。

#include<stdio.h>
int main()
{
	int a = 10;
	size_t sz = sizeof(a);
	printf("%zd\n", sz);	//运行结果:4
    //注:size_t类型的占位符是%zd
	return 0;
}

 总结一下

  • sizeof( )括号里可以放变量名,也可以放数据类型,还可以放表达式,表达式的括号还可以省略。如:sizeof a + c (这个留给读者验证)!
  • sizeof后面的表达式是不参与计算的
  • sizeof 的计算结果是size_t 类型的

算数操作符

+、-、*、/、%

前四个就是数学运算,这里先介绍 / 。除号两边都是整数,则结果为整数,有一个为小数,则结果为小数。

#include<stdio.h>
int main()
{
	int a = 22;
	int b = 3;
	float c = 2.2;
	printf("%d\n", a / b);    
	printf("%f\n", a / c);
	return 0;
}

运行结果:

第一个结果为7?22除以3的结果是7.33...,由于a跟b都是整数,所以结果只保留了整数部分。

再看一个例子:

#include <stdio.h> 
int main()
{
    int a = 5;
    int b = (a / 20) * 100; 
    printf("%d\n", b);
    return 0;
}

 按数学逻辑,b的值应该是25,但结果却是0,因为5 / 20的整数部分是0,再乘100还是0

% 表示求模运算,即返回两个整数相除的余数。这个运算符只能用于整数,不能用于浮点数。

#include <stdio.h> 
int main()
{
    int x = 6 % 4; 
    printf("%d\n", x); // 2 
    return 0;
}

 负数求模的规则是,结果的正负号由第⼀个运算数的正负号决定

#include <stdio.h> 
int main()
{
    printf("%d\n", 11 % -5); // 1 
    printf("%d\n",-11 % -5); // -1 
    printf("%d\n",-11 % 5); // -1 
    return 0;
}

 你可以这样计算:把负数全部变成正数 然后求余数,再根据第一个运算数的符号写出最终结果

赋值操作符=(从右往左)

#include <stdio.h> 
int main()
{
	int a = 10;    //初始化,把10赋值给a
	a = 200;       //又把200赋值给a,会把a之前储存的10覆盖掉
	printf("%d\n", a); //输出: 200
    return 0;
}

 连续赋值:

#include <stdio.h> 
int main()
{
	int a = 10;
	int b = 5, c = 7;
	c = b = a + 1;    //先把a+1赋值给b,即b=11,再把b赋值给c,即c=11。是从右往左
	printf("a: %d\n", a);    // 10
	printf("b: %d\n", b);    // 11
	printf("c: %d\n", c);    // 11
    return 0;
}

复合赋值:再代码中,我们可能会对一个变量进行自增、自减操作

#include <stdio.h> 
int main()
{
	int a = 10;
	a = a + 30;    //把a+30赋值给a.相当于a又增加了30
	printf("a: %d\n", a);    //40
    return 0;
}

C语言提供了更简便的写法:+=,注意这个整体是一个操作符,中间不可以有空格

#include <stdio.h> 
int main()
{
	int a = 10;
	a += 30;
    //a + = 30;    不可以有空格
	printf("a: %d\n", a);
    return 0;
}
   	a += 30 <==> a = a + 30
	a -= 30 <==> a = a - 30
	a *= 30 <==> a = a * 30
	a /= 30 <==> a = a / 30
	a %= 30 <==> a = a % 30

单目操作符++、--

啊?啥是单目?先介绍一下双目操作符吧,上面介绍的加减乘除取模,操作符两边都有一个数比如a+b,加号左边是a 右边是b,有两个变量就是双目操作符。那单目操作符就是只有一个变量呗

++是⼀种⾃增的操作符,⼜分为前置++和后置++,--是⼀种⾃减的操作符,也分为前置--和后置--.

前置++:先+1,后使用

#include <stdio.h> 
int main()
{
	int a = 10;
	int b = ++a; //++的操作数是a,是放在a的前面的,就是前置++ 
	printf("a=%d  b=%d\n", a, b);
    return 0;
}

运行结果: 

后置++:先使用,后+1

#include <stdio.h> 
int main()
{
	int a = 10;
	int b = a++; //++的操作数是a,是放在a的后面的,就是后置++ 
	printf("a=%d  b=%d\n", a, b);
    return 0;
}

 运行结果:

 前置--:先-1,后使用。后置--:先使用,后-1。这个就留个读者验证了~

强制类型转换

 直接看代码,a是整型,我偏偏想用%f打印成小数,就在a前面加上(float),表示把a强制转换成float类型。俗话说,强扭的⽠不甜,我们使⽤强制类型转换都是万不得已的时候使⽤,如果不需要强制类型转化就能实现代码,这样⾃然更好的。

printf()制定占位符的输出格式

上一节提到打印小数时我只想保留一位小数就要加上.1

printf("%.1f", 3.14);    //输出:3.1

当然,打印字符串也有类似用法。比如我想打印字符串的前5个字符:

printf("%.5s\n", "hello world"); //输出:hello

其实打印整数也可以限定

 第二个printf的占位符是%5d,意思是至少打印5位数,位数不够就在前面添空格。右对齐。

上面的代码用的是%-5d,意思是至少打印5位数,位数不够就在后面添空格。左对齐。

scanf

如果我想写个代码计算99*99,可能会这样:

#include <stdio.h>
int main()
{
    printf("%d\n", 99 * 99); // 9801
    return 0;
}

那如果计算别的乘法呢?比如我想任意输入两个数,让代码帮我算。。。

这就要用到scanf()函数了,它用于读取用户输入,在头文件stdio.h中。程序运行到这个语句时,会停下来等待用户输入

#include <stdio.h>
int main()
{
	int a, b;
	printf("请输入两个整数,用空格隔开\n");
	scanf("%d %d", &a, &b);	//输入:123 56 
    //scanf("%d %d\n", &a, &b); 这行是错误写法,不要在最后加上\n
    printf("%d\n", a * b);
    return 0;
}

scanf跟printf不同的是,它在变量前面加上了&(取地址符),scanf从屏幕读取数据后要存放哪里?你告诉它地址 它才能通过地址找到对应的变量进而把数据存放在里面。

注意:

  • scanf双引号里面的东西要跟用户输入的内容严格一致

上面的代码为啥算的结果是99呢?仔细看scanf双引号里面是%d,%d,想得到正确结果中间应当是逗号,而不是空格。而且代码中是英文逗号,你就要输入英文逗号;是中文符号,你就要输入中文符号。要严格一致。

这样输入才对嘛!

  • scanf会自动过滤空白字符,包括空格、制表符、换行符

我先输入99,敲下回车键后在输入88,也能得到答案。甚至可以像下面这样输入:

虽然中间隔了好多空格,但scanf会过滤掉它们。

但有个例外,%c不会忽略空白符:

 我输入a时不小心按了一下空格,导致并没有打印出字母a,而是打印了空格。

如果要强制跳过字符前的空白字符,可以写成scanf(" %c", &ch) ,即%c 前加上⼀个空格,表
示跳过零个或多个空白字符。如下面的代码

要特别说明一下%s,它的规则是,从当前第⼀个非空白字符开始读起,直到遇到空白字符(即空格、换⾏符、制表符等)为止

#include <stdio.h>
int main()
{
 //因为字符串是数组,所以要用数组储存。
	char c[11];	 //这行代码表示我创建了一个字符数组c,最多存储11个字符
	scanf("%s", c);    //输入:hello world
	printf("%s\n", c); //输出:hello
    return 0;
}

第一份非空白字符是h,往后第一个空白字符是空格,所以只读取了hello

  • scanf的返回值:返回值就是成功读取的数据个数

上面的代码成功读取两个数,所以返回值是2

上面的代码我输入99,然后想提前终止,就输入Ctrl+Z,这样scanf就只读取了一个数据,所以返回值是1

好了,以上就是本节全部内容了!有疑问的话欢迎在评论区留言哈!

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值