前几天复习的c基础
来源:互联网 发布:英伟达游戏优化怎么关 编辑:程序博客网 时间:2024/04/29 01:20
C学习
1 天:大致复习c的基本语法
1 const关键字
刚才提到,默认情况下,变量的值是可以不断改变的。不过,有时候我们会希望变量的值只在定义的时候初始化一次,以后都不能再改变,这个时候我们就可以使用const关键字来修饰变量。
const int i=2;
2.printf支持的格式符
除开%d,printf还支持很多格式符,如下表所示(红色表示常用),这份表格的内容不用去死记,用到时再回来查资料即可
printf也可以输出常量
1 #include <stdio.h>
2
3 intmain()
4 {
5
6 printf("输出的常量为%d\n",11);
7
8 return0;
9 }
下面的表格描述了在不同编译器环境下的存储空间占用情况
2> 上述变量a、b在内存中的存储情况大致如下表所示:
(注:"存储的内容"那一列的一个小格子就代表一个字节,"地址"那一列是指每个字节的地址)
•从图中可以看出,变量b占用了内存地址从ffc1~ffc4的4个字节,变量a占用了内存地址为ffc5的1个字节。每个字节都有自己的地址,其实变量也有地址。变量存储单元的第一个字节的地址就是该变量的地址。变量a的地址是ffc5,变量b的地址是ffc1。
•内存寻址是从大到小的,也就是说做什么事都会先从内存地址较大的字节开始,因此系统会优先分配地址值较大的字节给变量。由于是先定义变量a、后定义变量b,因此你会看到变量a的地址ffc5比变量b的地址ffc1大。
•注意看表格中变量b存储的内容,变量b的二进制形式是:0000 0000 0000 0000 0000 0000 0000 1010。由于内存寻址是从大到小的,所以是从内存地址最大的字节开始存储数据,存放顺序是ffc4 -> ffc3 -> ffc2 -> ffc1,所以把前面的0000 0000都放在ffc2~ffc4中,最后面的八位0000 1010放在ffc1中。
printf("变量a的地址是:%p", &a);
三、负数的二进制形式
1 intmain()
2 {
3 int b = -10;
4 return0;
5 }
在第3行定义了一个整型变量,它的值是-10。-10在内存中怎样存储的呢?其实任何数值在内存中都是以补码的形式存储的。
- •正数的补码与原码相同。比如9的原码和补码都是1001
- •负数的补码等于它正数的原码取反后再+1。(取反的意思就是0变1、1变0
代码块其实就是用大括号{}括住的一块代码。
1 intmain()
2 {
3 {
4 int a =10;
5
6 printf("a=%d", a);
7 }
8
9 a = 9;
10
11 return0;
12 }
- •注意第3~7行的大括号,这就是一个代码块
- •当执行到第4行时,系统会分配内存给变量a
- •当代码块执行完毕,也就是执行完第6行代码后,变量a所占用的内存就会被系统回收
- •因此,变量a的作用范围是从定义它的那行开始,一直到它所在的大括号{}结束,也就是第4~7行,离开这个范围,变量a就失效了
- •所以,上面的程序是编译失败的,第9行代码是错误的,变量a在第7行的时候已经失效了,不可能在第9行使用
3.数值越界
1> 例子演示
前面已经看到,每种数据类型都有自己的取值范围。如果给一个变量赋值了一个超出取值范围的数值,那后果会不堪设想。
1 #include <stdio.h>
2
3 intmain()
4 {
5 int c =1024 * 1024 *1024 * 4;
6
7 printf("%d\n", c);
8 return0;
9 }
我们都知道,int类型能保存的最大值是231-1。在第5行给int类型的变量c赋值一个比231-1大的数值:232(1024是210)
先看看在终端中的输出结果:,可以看出输出的值是0。
2> 结果分析
我们可以简单分析一下为什么将232赋值给变量c之后输出的是0。232的二进制形式是:1 0000 0000 0000 0000 0000 0000 0000 0000,一共有33位二进制数。变量c占用了4个字节,只能容纳32位二进制数,而且内存寻址是从大到小的,因此,变量c在内存中的存储形式是0000 0000 0000 0000 0000 0000 0000 0000,也就是0,最前面的那个1就不属于变量c的了。
3.字符型变量还可以当做整型变量使用
1个字符型变量占用1个字节,共8位,因此取值范围是-27~27-1。在这个范围内,你完全可以将字符型变量当做整型变量来使用。
1 #include <stdio.h>
2
3int main()
4 {
5 char c1 = -10;
6
7 char c2 =120;
8
9 printf("c1=%d c2=%d \n", c1, c2);
10 return0;
11 }
由于第9行用的是%d,表示以十进制整数格式输出,输出结果:。因此,如果使用的整数不是很大的话,可以使用char代替int,这样的话,更节省内存开销。
些说明符一般就是用来修饰int类型的,所以在使用时可以省略int
1//下面两种写法是等价的
2 short int s1 = 1;
3 short s2 =1;
4
5 //下面两种写法是等价的
6 long int l1 = 2;
7 long l2 =2;
8
9 // 可以连续使用2个long
10 long long ll = 10;
11
12 //下面两种写法是等价的
13 signed int si1 = 3;
14 signed si2 =3;
15
16 //下面两种写法是等价的
17 unsignedint us1 = 4;
18 unsigned us2 =4;
19
20 //也可以同时使用2种修饰符
21 signedshort int ss =5;
22 unsignedlong int ul =5;
3.short和long
1> short和long可以提供不同长度的整型数,也就是可以改变整型数的取值范围。在64bit编译器环境下,int占用4个字节(32bit),取值范围是-231~231-1;short占用2个字节(16bit),取值范围是-215~215-1;long占用8个字节(64bit),取值范围是-263~263-1
2> 总结一下:在64位编译器环境下,short占2个字节(16位),int占4个字节(32位),long占8个字节(64位)。因此,如果使用的整数不是很大的话,可以使用short代替int,这样的话,更节省内存开销。
3> 世界上的编译器林林总总,不同编译器环境下,int、short、long的取值范围和占用的长度又是不一样的。比如在16bit编译器环境下,long只占用4个字节。不过幸运的是,ANSI \ ISO制定了以下规则:
- •short跟int至少为16位(2字节)
- •long至少为32位(4字节)
- •short的长度不能大于int,int的长度不能大于long
- •char一定为为8位(1字节),毕竟char是我们编程能用的最小数据类型
4> 可以连续使用2个long,也就是long long。一般来说,long long的范围是不小于long的,比如在32bit编译器环境下,long long占用8个字节,long占用4个字节。不过在64bit编译器环境下,long long跟long是一样的,都占用8个字节。
5> 还有一点要明确的是:short int等价于short,long int等价于long,long long int等价于long long
4.long的使用注意
1> 常量
long和int都能够存储整型常量,为了区分long和int,一般会在整型常量后面加个小写字母l,比如100l,表示long类型的常量。如果是long long类型呢,就加2个l,比如100ll。如果什么都不加,就是int类型的常量。因此,100是int类型的常量,100l是long类型的常量,100ll是long long类型的常量。
1 intmain()
2 {
3 int a =100;
4
5 long b =100l;
6
7 longlong c = 100ll;
8
9 return0;
10 }
变量a、b、c最终存储的值其实都是100,只不过占用的字节不相同,变量a用4个字节来存储100,变量b、c则用8个字节来存储100。
其实,你直接将100赋值给long类型的变量也是没问题的,照样使用。因为100是个int类型的常量,只要有4个字节,就能存储它,而long类型的变量b有8个字节,那肯定可以装下100啦。
1 intmain()
2 {
3 long b =100;
4
5 return0;
6 }
2> 输出
1 #include <stdio.h>
2
3 intmain()
4 {
5 long a =100000000000l;
6
7 printf("%d\n", a);
8 return0;
9 }
在第5行定义了long类型变量a,在第7行尝试输出a的值。注意了,这里用的是%d,表示以十进制整数格式输出,%d会把a当做int类型来输出,它认为a是4个字节的。由于a是long类型的,占用8个字节,但是输出a的时候,只会取其中4个字节的内容进行输出,所以输出结果是:
又是传说的垃圾数据
那怎样才能完整地输出long类型呢?应该用格式符%ld
1 #include <stdio.h>
2
3 intmain()
4 {
5 long a =100000000000l;
6
7 printf("%ld\n", a);
8 return0;
9 }
注意第7行,双引号里面的是%ld,表示输出1个long类型的整数,这时候的输出结果是:
如果是long long类型,应该用%lld
1 #include <stdio.h>
2
3 intmain()
4 {
5 longlong a = 100000000000ll;
6
7 printf("%lld\n", a);
8 return0;
9 }
5.signed和unsigned
1> 首先要明确的:signed int等价于signed,unsigned int等价于unsigned
2> signed和unsigned的区别就是它们的最高位是否要当做符号位,并不会像short和long那样改变数据的长度,即所占的字节数。
- •signed:表示有符号,也就是说最高位要当做符号位,所以包括正数、负数和0。其实int的最高位本来就是符号位,已经包括了正负数和0了,因此signed和int是一样的,signed等价于signed int,也等价于int。signed的取值范围是-231~ 231 - 1
- •unsigned:表示无符号,也就是说最高位并不当做符号位,所以不包括负数。在64bit编译器环境下面,int占用4个字节(32bit),因此unsigned的取值范围是:0000 0000 0000 0000 0000 0000 0000 0000 ~ 1111 1111 1111 1111 1111 1111 1111 1111,也就是0 ~ 232 - 1
7.不同数据类型所占用的存储空间
第二天
2.在标准C语言中,函数的定义顺序是有讲究的,默认情况下,只有后面定义的函数才可以调用前面定义过的函数
1 int sum(int a,int b) {
2 return a +b;
3 }
4
5 intmain()
6 {
7 int c = sum(1,4);
8 return0;
9 }
第5行定义的main函数调用了第1行的sum函数,这是合法的。如果调换下sum函数和main函数的顺序,在标准的C编译器环境下是不合法的(不过在Xcode中只是警告,Xcode中用的是GCC编译器)
3.如果想把其他函数的定义写在main函数后面,而且main函数能正常调用这些函数,那就必须在main函数前面作一下函数的声明
1//只是做个函数声明,并不用实现
2 int sum(int a,int b);
3
4 int main()
5 {
6 int c = sum(1,4);
7 return0;
8 }
9
10 //函数的定义(实现)
11 int sum(int a,int b) {
12 return a +b;
13 }
4.在大型的C程序中,为了分模块进行开发,一般会将函数的声明和定义(即实现)分别放在2个文件中,函数声明放在.h头文件中,函数定义放在.c源文件中
下面我们将sum函数的声明和定义分别放在sum.h和sum.c中
说到这里,有人可能有疑惑:可不可以在main.c中包含sum.c文件,不要sum.h文件了?
大家都知道#include的功能是拷贝内容,因此上面的代码等效于:
这么一看,语法上是绝对没有问题的,但是绝对运行不起来,在链接时会出错。原因:编译器会编译所有的.c源文件,这里包括main.c、sum.c,编译成功后生成sum.obj、main.obj文件,当链接这两个文件时链接器会发现sum.obj和main.obj里面都有sum函数的定义,于是报"标识符重复"的错误。
printf("%5d\n", n);
printf("%-5du\n", m);
printf("%-8.2f%10.3f",a,a);
大家都知道,数组名代表着整个数组的地址,如果一维数组的名字作为函数实参,传递的是整个数组,即形参数组和实参数组完全等同,是存放在同一存储空间的同一个数组。这样形参数组修改时,实参数组也同时被修改了。形参数组的元素个数可以省略。
//b是test函数的形参(形式参数)
void test(int b[]) {// 也可以写int b[3]
b[0] =9;
}
int main()
{
int a[3];
a[0] =10;
printf("函数调用前的a[0]:%d\n", a[0]);
test(a); // a是test函数的实参(实际参数)
printf("函数调用后的a[0]:%d", a[0]);
return 0;
}
些人可能想不明白,为什么可以省略行数,但不可以省略列数。也有人可能会问,可不可以只指定行数,但是省略列数?
其实这个问题很简单,如果我们这样写:
int a[2][] = {1,2, 3,4, 5, 6}; // 错误写法
大家都知道,二维数组会先存放第1行的元素,由于不确定列数,也就是不确定第1行要存放多少个元素,所以这里会产生很多种情况,可能1、2是属于第1行的,也可能1、2、3、4是第一行的,甚至1、2、3、4、5、6全部都是属于第1行的
第三天
字符串
Gets();puts();一次一个字符串puts函数输出一个字符串后会自动换行。gets可以读入包含空格、tab的字符串,直到遇到回车为止;scanf不能用来读取空格、tab。
2.字符串数组的初始化
char names[2][10] = { {'J','a','y','\0'}, {'J','i','m','\0'} };
char names2[2][10] = { {"Jay"}, {"Jim"} };
char names3[2][10] = {"Jay", "Jim" };
8 char c[3] = {‘’e’,’f’,’’\0};
当我们使用类似第8行的初始化方式时,系统会自动在字符串尾部加上一个\0结束符
凡是有双引号引得都默认加上\0了,不需要自己加
1.字符输出函数putchar
putchar(65); //A
putchar('A'); // A
int a = 65;
putchar(a); // A
上面的3种用法,输出的都是大写字母A。
* putchar一次只能输出一个字符,而printf可以同时输出多个字符
printf("%c %c %c",'A', 'B', 'a');
2.字符输入函数getchar
char c;
c = getchar();
getchar会将用户输入的字符赋值给变量c。
* getchar函数可以读入空格、TAB,直到遇到回车为止。scanf则不能读入空格和TAB。
* getchar一次只能读入一个字符。scanf则可以同时接收多个字符。
* getchar还能读入回车换行符,这时候你要敲2次回车键。第1次敲的回车换行符被getchar读入,第2次敲的回车键代表输入结束。
- 前几天复习的c基础
- C基础的复习
- 复习潭浩强的c基础
- c语言的基础复习
- 复习 C 指针的基础概念
- C语言基础复习
- C指针基础复习
- C语言基础复习
- c语言基础复习一
- C++Primer Plus 基础复习
- C++(基础班)上机复习
- 前几天的陌生电话
- 前几天发生的事情
- 前几天交的作业
- 前几天的工作记录
- android前几天的日期
- C语言的基础复习——scanf使用注意
- C的复习
- 黑马程序员_单例和享元设计模式
- 一个PHP图表绘制类 - Chart
- JpGraph简介 --功能超级强大的PHP画图库
- 科普文---计算机是如何启动的?
- 经典数据结构--简单链表
- 前几天复习的c基础
- Coins
- PHP实现常见排序算法
- C++之new和delete的用法
- OCP-1Z0-053-V12.02-407题
- registerWithTouchDispatcher()函数的使用
- this.成员变量:当前类的变量,this.方法:当前运行类的方法!
- 如何解决网站没有排名
- 让office2007支持MathType5.2