前言
提示:/*该文章作为个人学习且分享使用,若有侵权,请联系我删除*/
本文章起名为初识C语言,顾名思义,即简单地、浅显地知晓一下C语言,大概需要学到哪些知识,不做深层的解读,本文章适合初学者进行学习,有错误还请私信我纠正。
提示:以下是本篇文章正文内容,下面案例可供参考
一、什么是C语言?
语言我们大家都知道,像我们现实生活中交流都需要用汉语语言来沟通学习交流,那什么是C语言?C语言通俗来讲,就是人与计算机进行交流,是一门通用的计算机编程语言,广泛应用于底层的开发,像底层的软件开发,如操作系统、驱动层软件的开发。
计算机C语言的发展历史:最初的计算机语言是利用2进制(机器语言)来编写,用2进制来编写太复杂了,于是人们便采用了助记符来编写程序,以此发展到汇编语言,而后发展到B语言,最后发展成现在的C语言。
C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
C语言是一门面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同。
其编译器主要有Clang(MacOS系统)、GCC(Linux系统)、WIN-TC、SUBLIME、MSVC(Microsoft Visual C++,用于Windows系统 )等
二、第一个C语言程序
#include <stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
程序的运行从main函数开始,在整个工程中,main函数只存在一个。
三、基本数据类型
char //字符数据类型 short //短整型 int //整形 long //长整型 long long //更长的整形 float //单精度浮点数 double //双精度浮点数
基本的数据类型会被分为有符号(signed)和无符号(unsigned)两大类。一般写的数据类型没有在前面注明(unsigned char)的情况下,默认为有符号类型。 那么有符号的数据类型和无符号的数据类型有什么区别? 区别就是在内存的存储中,符号位是1还是0,具体的还请翻阅数据存储及内存相关的知识。在这个章节咱们先了解即可。
1. 有符号整型家族
类型名称 | 大小(字节数) | 取值范围 |
---|
signed char | 1 | -2^ 7(-128) ~ 2^7-1(127) | short int 或 short | 2 | -2^ 15(-32 768) ~ 2^15-1(32 767) | int | 4 | -2^ 31(-2 147 483 648) ~ 2^31-1(2 147 483 647) | long int 或 long | 4 | -2^ 31(-2 147 483 648) ~ 2^31-1(2 147 483 647) | long long int 或 long long | 8 | -2^ 63(-9.2233720368548e+18) ~ 2^63-1(9.2233720368548e+18) |
咱们试着在编译器中用**sizeof() **(sizeof()是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小。)来打印各种基本数据类型的大小。
2. 无符号整型家族
类型名称 | 大小(字节) | 取值范围 |
---|
unsigned char | 1 | 0 ~ 2^8-1(255) | unsigned short int 或 unsigned short | 2 | 0 ~ 2^16-1(65 535) | unsigned int | 4 | 0 ~ 2^32-1(4 294 967 295) | unsigned long int 或 unsigned long | 4 | 0 ~ 2^32-1(4 294 967 295) | unsigned long long int 或 unsigned long long | 8 | 0 ~ 2^64-1(1.844674407371e+19) |
3. 浮点类型家族
类型名称 | 大小(字节) | 取值范围 |
---|
float | 4 | -/+3.4e38(精确到6位小数) | double | 8 | -/+1.7e308(精确到15位小数) | long double | 12 | -/+1.19e4932(精确到18位小数) |
以上基本数据类型的单位都是字节(byte),数据存储中是以“字节”(Byte)为单位,数据传输大多是以比特(bit)为单位,一个位就代表一个0或1(即二进制),每8个位(bit,简写为b)组成一个字节(Byte,简写为B),是最小一级的信息单位。
4.C语言基本单位的换算
那么C语言中,有哪些单位,这些单位之间又是如何转换运算呢?
Byte -->1 Byte = 8 bit KB --> 1KB = 1024Byte MB --> 1MB = 1024KB GB --> 1GB = 1024MB TB --> 1TB = 1024GB PB --> 1PB = 1024TB ……
四、变量和常量
1.变量
定义格式:数据类型+变量名 = 字面值(XXX) ;
int age = 50; float weight = 130.5f; char name = “张三”;
(局部)变量在创建时未初始化一般会给随机值,但是有的编译器会报错。为了避免这样的错误,我们一般会在创建时就给初始值。
int main()
{
int a = 0;
return 0
}
变量的命名规则
- 只能由字母(包括大写和小写)、数字和下划线( _ )组成。
- 不能以数字开头。
- 长度不能超过
63 个字符。 - 变量名中区分大小写的。
- 变量名不能使用关键字
注意:在起变量名时不能太随意,变量名最好见名知意。
变量的分类
局部变量:局部变量是在函数内部定义的变量,只能在函数内部或者局部变量所在的局部范围内使用。 全局变量:是在函数外部定义的变量(没有定义在某一个函数内),适用于整个工程,所有函数内部都可以使用这个变量。
当局部变量和全局变量同名的时候,则局部变量优先。 用代码说明如下:
#include <stdio.h>
int gl_val = 123;
int main()
{
int local = 234;
int gl_val = 456;
printf("gl_val = %d\n", gl_val);
return 0;
}
变量的作用域和生命周期
作用域:
作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效可用的而限定这个名字的可用性的代码范围就是这个名字的作用域。
- 局部变量的作用域是变量所在的局部范围。
- 全局变量的作用域是整个工程。
这里就出现报错,局部变量b,出了所在的局部范围再打印b,程序会报错,出现在44行。 生命周期:
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段
- 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
- 全局变量的生命周期是:整个程序的生命周期。
int main()
{
{
int a = 10;
printf("%d\n", a);
}
printf("%d\n", a);
return 0;
}
2.常量
- 字面常量
const 修饰的常变量d(本质还是一个变量,相当于用const给上了一把锁,不能直接被修改)#define 定义的标识符常量- 枚举常量
int main()
{
const int num = 10;
printf("%d\n", num);
num = 20;
}
int main()
{
#define MAX 10000
MAX = 20000;
printf("MAX = %d\n",MAX);
return 0;
}
enum RGB
{
red = 10,
green,
blue
};
int main()
{
enum RGB r = red;
printf("%d\n",red);
printf("%d\n",green);
printf("%d\n",blue);
return 0;
}
五、字符串+转义字符+注释
字符串
“hello world” 这种由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字符串。
'\0' 是字符串的结束标志
int main()
{
char arr1[] = "abcde";
char arr2[] = {'a','b','c','d','e'};
printf("%s\n",arr1);
printf("%s\n",arr2);
}
如果我们在arr2数组的后面添加个‘\0’,这时在‘e’后面找到了\0,就会结束打印
\0 不占据字符串长度,但占据内存空间长度
int main()
{
char arr1[] = "abc";
char arr2[] = {'a', 'b', 'c'};
int len = strlen(arr1);
printf("%d\n", len);
len = strlen(arr2);
printf("%d\n", len);
printf("arr1的长度是%d",sizeof(arr1));
return 0;
}
转义字符
int main()
{
printf("abcd\0ef");
return 0;
}
什么是转义字符,其实我们在上面就讲过,‘\0’ 就是一个转义字符,在0的前面添加一个反斜杠,就会改变它原有的含义,此时它的含义就不是0这个单纯的值了,而是作为结束符来使用,此时的“abcd\0ef” 打印出来就是abcd 。 打印出单引号和双引号
#include<stdio.h>
int main()
{
printf("\"");
printf("\n");
printf("\'");
return 0;
}
更多常见转义字符,详细见表格。
转义字符 | 释义 |
---|
? | 表示一个问号,在书写连续多个问号时使用,防止他们被解析成三字母词 | \0 | 常用作字符串的结束标志 | \’ | 表示输出一个单引号 | \" | 表示输出一个双引号 | \a | 警告字符,电脑会蜂鸣 | \b | 退格符 | \f | 进纸符 | \n | 换行 | \r | 回车 | \t | 水平制表符 | \v | 垂直制表符 | \ddd | ddd表示1~3个八进制数字。如 \130 X | \xhh | hh表示两个十六进制数字。 如\x30 0 |
\ddd 和 \xhh 表示什么意思呢? 转换它为十进制,所对应的ASCII码表中的字符。
int main()
{
printf("%c",'\130');
printf("%c",'\x30');
return 0;
}
注释
哪些情况下我们可以使用注释呢?
- 代码中有不需要的代码可以直接删除,也可以注释掉
- 代码中有些代码比较难懂,可以加一下注释文字来解释它
- 注释有两种风格:
C语言风格的注释 /xxxxxx/ 缺陷:不能嵌套注释 C++风格的注释 //xxxxxxxx 可以注释一行也可以注释多行
六、选择语句
1.if语句和switch语句
if 语句的语法格式为: if(条件判断) {
条件判断为真,就执行该大括号里的内容
}else { 条件判断为假,执行此括号里的内容 }
#include<stdio.h>
int main()
{
printf("好好努力敲代码吗?(1/0)\n");
int a;
scanf("%d",&a);
if(1 == a)
{
printf("未来拿到高薪offer");
}else
{
printf("未来吃土");
}
return 0;
}
if……else多分支语句 if(条件判断1) { 条件判断1为真执行此大括号内的语句; }else if(条件判断2) { 条件判断2为真执行此大括号内的语句; }else if(条件判断3) { 条件判断3为真执行此大括号内的语句; }else{ 以上条件判断皆为假则执行此大括号内的语句 }
#include<stdio.h>
int main()
{
printf("请输入你的成绩(0-100)\n");
int score;
scanf("%d", &score);
if (score == 100)
{
printf("恭喜你获得了满分,奖励你100人民币!");
}
else if (score >= 80 && score < 100)
{
printf("成绩优异,奖励你50人民币!");
}
else if (score >= 60 && score < 80)
{
printf("成绩合格,继续努力。");
}
else if (score >= 0 && score < 60)
{
printf("成绩不合格,需要重修!");
}
else
{
printf("输入有误,请重新输入!");
}
return 0;
}
2. switch语句
switch 语句的语法格式如下
switch(变量表达式){ case 常量表达式1:语句1; case 常量表达式2: 语句2; case 常量表达式3: 语句3; … case 常量表达式n: 语句n; default: 语句n+1; } 当变量表达式所表达的量与其中一个case语句中的常量相符时,就执行此case语句后面的语句,并依次下去执行后面所有case语句中的语句,除非遇到break;语句跳出switch语句为止。如果变量表达式的量与所有case语句的常量都不相符,就执行default语句中的语句
int main ()
{
char grade = 'B';
switch(grade)
{
case 'A' :
printf("很棒!\n" );
break;
case 'B' :
case 'C' :
printf("做得好\n" );
break;
case 'D' :
printf("您通过了\n" );
break;
case 'F' :
printf("最好再试一下\n" );
break;
default :
printf("无效的成绩\n" );
}
printf("您的成绩是 %c\n", grade );
return 0;
}
七、循环控制语句
循环语句:
while语句 for语句 do……while语句
1.while语句
while 循环的语法形式为 while (表达式) { 执行内容(循环体); }
当表达式为真,则执行下面的循环体;循环体执行完之后再判断表达式是否为真,如果为真,再次执行下面的循环体;然后再判断表达式是否为真……就这样一直循环下去,直到表达式为假,就跳出循环。
#include <stdio.h>
int main()
{
printf("努力敲代码\n");
int line = 0;
while (line <= 50000)
{
line++;
printf("%d:继续努力敲代码\n",line);
}
if (line >= 50000)
printf("拿到高薪offer\n");
return 0;
}
2.for语句
for 循环的一般形式为: for(表达式1; 表达式2; 表达式3) { 执行内容(循环体); } 它的运行过程为:
-
先执行“表达式1”。 再执行“表达式2”,如果它的值为真(非0),则执行循环体,否则结束循环。 -
执行完循环体后再执行“表达式3”。 -
重复执行步骤 2和 步骤3,直到“表达式2”的值为假,就结束循环
#include <stdio.h>
int main(){
int i, sum=0;
for(i = 1; i <= 100; i++){
sum += i;
}
printf("%d\n",sum);
return 0;
}
3. do……while语句
do……while 语句的语法格式为:
do { 循环体; }while(表达式);
do …… while 循环与 while 循环不同的是:先执行一次语句,再判断表达式是否为真,然后决定是否再执行一次语句或者表达式为假跳出循环。
#include <stdio.h>
int main()
{
int a = 10;
do
{
printf("a 的值: %d\n", a);
a = a + 1;
}while( a < 20 );
return 0;
}
八、 控制语句
注:break不能用于除循环语句和switch语句之外的任何其他语句中
break 语句:终止循环或 switch 语句,程序会跳出循环体,将继续执行紧接着的语句或switch 的下一条语句。 continue 语句:结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判定。 goto 语句: 将控制转移到被标记的语句。但是不建议在程序中使用 goto 语句
九、函数
介绍两个常用的输入输出函数
1.scanf和printf函数
讲一讲scanf() 函数和printf() 函数,这两个函数是C语言中常用的函数,为输入输出函数,两个函数使用前均需要使用头文件#include <stdio.h> (standard input &output,意为标准输入输出)
printf函数:用于向标准输出设备按规定格式输出信息。 scanf函数:是格式输入函数,即按用户指定的格式从键盘上把数据输入到指定的变量之中
scanf函数
# include<stdio.h>
int main()
{
int x = 0;
int y = 0;
scanf("%d %f",&x,&y)
return 0;
}
有关scanf函数的返回值问题
#include<stido.h>
int main()
{
int a = 0;
int b = 0;
scanf("%d %f",&x,&y)
return 0;
}
scanf读取数据,如果返回正常的话,返回的是读取到的数据的个数 。 如果读取失败,那么返回的是EOF ,全称为“End Of File”(文件的结束标志), EOF 对应的值是多少?在编译器中输入EOF并点击转到定义,可以看出它的值为-1。 那么scanf的返回值有什么用呢? 可以适用于多次输入、多组输入的标准,如何编写?以以下题目为例
据说智商140以上者称为天才,KiKi想知道他自己是不是天才,请帮他编程判断。输入一个整数表示一个人的智商,如果大于等于140,则表明他是一个天才,输出“Genius”
输入描述要求:多组输入,每行输入包括一个整数表示的智商。 输出描述要求:针对每行输入,输出“Genius”
#include<stido.h>
int main()
{
int iq = 0;
while( scanf("%d",&iq) != EOF)
{
if(iq >= 140)
printf("Genius\n");
}
return 0;
}
printf函数
printf函数使用输出有两种格式,一种是直接引用字符串的形式输出,第二种类似于scanf函数,以格式化字符串的形式输出。
1.第一种,直接进行输出,不按需求格式化,引用格式为:printf(“输出数据\n”);
#include<stido.h>
int main()
{
printf("Hello,World!")
return 0;
}
2.第二种格式化字符串进行输出,引用格式为:printf(" 格式化字符串 ", 待输出参数 )
#include<stido.h>
int main()
{
int a = 1;
printf("%d\n",a);
float b = 2;
printf("%f\n",b);
return 0;
}
更多格式字符见以下表格
格式化字符 | 释义 |
---|
%d | 以十进制形式输出带符号整数(正数不输出符号) | %o | 以八进制形式输出无符号整数(不输出前缀0) | %x,%X | 以十六进制形式输出无符号整数(不输出前缀Ox) | %u | 以十进制形式输出无符号整数 | %f | 以小数形式输出单、双精度实数 | %c | 输出单个字符 | %s | 输出字符串 | %p | 输出指针地址 |
2. 自定义函数
/**仅先了解有返回值的函数&*/。 函数有什么用呢? 比如说: 求两个数的和,我们平常最直接的方法是按以下方法写
#include<stido.h>
int main()
{
int m = 0;
int n = 0;
scanf("%d %d",&m,&n);
int sum = m + n;
printf("%d",sum);
return 0;
}
如果需要再写几个加法呢,我们需要再定义几个变量如以上方法去写吗?太过于麻烦了! 这时我们直接写一个函数,再需要几次,直接调用几次使用就行。 那么如何把加法的功能写成函数呢?
#include<stido.h>
int Add(int a,int b)
{
int z = a + b;
return z;
}
int main()
{
int m = 10;
int n = 20;
int sum = Add(m,n);
printf("%d",sum);
return 0;
}
如何理解这个加法计算的函数的过程呢?
观察以下流程图,我们可以把函数类比成工厂,工厂中的原材料A和原材料B看成函数中的传进的参数m与n,工厂里的加工操作则可以看成是函数中的计算,再经过加工处理之后,也就生产出可以售卖给自己的产品,同样如此,函数经过在内部的计算之后,得到的结果就是通过return 返回z值,调用函数,才能将得到的结果传到sum中,再通过sum打印出来。
十、数组
/*这里只简单地概述一下一维数组的内容/ 要存储1-10的数字,怎么存储? C语言中给了数组的定义:一组相同类型元素的集合
1.数组的创建
# include<stdio.h>
int main()
{
int arr[5];
char ch[15];
return 0;
}
2.数组的初始化
# include<stdio.h>
int main()
{
int a = 0;
int arr1[5] = {0};
int arr[5] = {1,2,3,4,5};
char ch1[3] = "abc";
char ch2[3] = {'a','b','c'};
return 0;
}
查看数组的元素 [按f10调试->监视窗口]
#include<stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5};
return 0;
}
3.数组的下标
C语言规定:数组的每个元素都有一个下标,下标是从0开始的。 数组可以通过下标来访问的。
比如:int arr[10] = {1}; 如果数组有十个元素,其下标的范围为0 ~ 9 数组的元素需要通过数组的下标来访问。
# include<stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
printf("%d",arr[4]);
return 0;
}
遍历数组,将数组中的元素全部打印出来
#include <stdio.h>
int main()
{
int i = 0;
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
for(i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
十一、操作符(运算符)
简单地初步认识就行,不作深入了解。
算数操作符:+ ? ?- ? ? * ? ?/ ? ? %
# include<stdio.h>
int main()
{
int a = 5,b = 10 ,c;
c = a + b;
c = b - a;
c = a * b;
c = b / a;
c = b % 3;
return 0;
}
%操作符只能作用于整数
# include<stdio.h>
int main()
{
float m = 10.0f;
float n = 3.0f;
printf("%f\n",a / b);
float a = 10 / 3;
float b = 10.0f / 3;
printf("%f\n",a);
printf("%f\n",b);
return 0;
}
移位操作符:>> ? ? << 移动的是内存中的二进制位
位操作符:& ? ? |? ? ^ 按位与、按位或、按位异或
赋值操作符:= ? ? += ? ? -= ? ? *= ? ? /== ? ? &= ? ? ^= ? ? |= ? ? >>= ? ? <<=
# include<stdio.h>
int main()
{
int a = 0;
a = 10;
a += 20 ;
return 0;
}
单目操作符: ? ! ? ? ? ? ? ? 逻辑反操作 ? - ? ? ? ? ? ?负值 ? + ? ? ? ? ? 正值 ?& ? ? ? ? ? 取地址 ?sizeof ? ? 操作数的类型长度(以字节为单位) ?~ ? ? ? ?? ? 对一个数的二进制按位取反 ?– ? ? ? ? ? ?前置、后置– ?++ ? ? ? ? 前置、后置++ ?* ? ? ? ? ? ? 间接访问操作符(解引用操作符) ?(类型) ? ? 强制类型转换
加上! 逻辑反操作把真变为假,把假变为真。
#include<stdio.h>
int main()
{
int flag = 0;
if(flag)
{
printf("hehe\n");
}
if(!flag)
{
printf("haha\n");
}
return 0;
}
sizeof 用来计算变量或者类型的大小
#include<stdio.h>
int main()
{
int a = 10;
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(int));
int arr[10] = {0};
printf("%d\n",sizeof(arr));
printf("%d\n",sizeof(arr[0]));
int sz = sizeof(arr)/sizeof(arr[0]);
printf("%d\n",sz);
return 0;
}
自增(++ )和自减(-- )
#include <stdio.h>
int main()
{
int a = 10;
int b = a--;
printf("a = %d b = %d",a,b);
int a = 10;
int b = --a;
printf("a = %d b =%d\n",a,b);
return 0;
}
() 强制类型转换
#include <stdio.h>
int main()
{
int a = 3.14;
float f = 3.14;
int a = (int)3.14;
float f = (float)3.14;
return 0;
}
关系操作符: ?> ?= ?< ?<= ?!= ????????用于测试“不相等” ?== ?????? 用于测试“相等”
逻辑操作符: ?&& ? ? ? 逻辑与 ?|| ? ? ? ? ? 逻辑或
逻辑操作符的运用
#include <stdio.h>
int main()
{
char input = ' ';
scanf("%c",&input);
if('a' < input && input < 'z' || 'A' < input && input < 'Z' )
{
printf("是字母");
}else
printf("不是字母");
return 0;
}
条件操作符(三目操作符): exp1 ? exp2 : exp3 用法:当exp1为真就执行exp2的结果,为假则执行exp3的结果。
#include<stdio.h>
int main()
{
int a = 0;
int b = 0;
int max = 0;
scanf("%d %d",a,b);
max = (a > b ? a : b);
printf("%d",max);
return 0;
}
逗号表达式: exp1, exp2, exp3,……expN
逗号表表达式的特点是:表达式从左向右依次计算,但是整个表达式的结果为最后一个表达式的结果。
#include<stdio.h>
int main()
{
int a = 10;
int b = 20;
int c = 30;
int d = (a += 10,b -= 15,c = a + b);
printf("%d",d);
return 0;
}
下标引用、函数调用和结构成员 [ ]??()??. ?? ->
十二、 常见关键字
C语言中提供了32 个关键字,而这些关键字是C语言中已经预先设定好的,我们用户自己不能创造关键字。
auto ?break ? case ? char ? const ? continue ?default ?do ? double? else? enum ? extern? float ?for ? goto ? if ?int ? long ? register ? return ? short ?signed ?sizeof ? static ?struct ?switch typedef ? union unsigned ? void ?volatile ?while
循环语句中用到的关键字:
break、continue、do……while、while、for
分支语句关键字:
switch、case、if……else、goto
函数中的返回值:
return
变量中常用到的:
auto、register、static
关键字auto 和register
#include<stdio.h>
int main()
{
auto int a = 10;
register int num = 100;
return 0;
}
关键字static
static是用来修饰变量和函数的
- 修饰局部变量-称为静态局部变量
- 修饰全局变量-称为静态全局变量
- 修饰函数-称为静态函数
1、修饰局部变量
#include<stdio.h>
void test()
{
int a = 1;
a++;
printf("%d ",a);
}
int main()
{
int i = 0;
while(i < 10)
{
test();
i++;
}
return 0;
}
在局部变量a的前面加上static结果就不一样了
#include<stdio.h>
void test()
{
static int a = 1;
a++;
printf("%d ",a);
}
int main()
{
int i = 0;
while(i < 10)
{
test();
i++;
}
return 0;
}
为什么呢? 在内存中,主要分为三个区域,栈区、堆区和静态区域。栈区存放局部变量、形式参数,堆区主要用于动态内存分配,而静态区主要存放静态变量和全局变量。
一个普通的局部变量是存放在栈区的,而被static修饰的局部变量,是存放在内存的静态区的,本质上改变了在内存中的存储位置,使得局部变量出了作用域不会销毁,影响了变量的生命周期(作用域不受影响)。
2、修饰全局变量 再新建一个add.c的源文件,写入一个全局变量g_val 我们发现,直接使用会有报错显示“未声明的标识符”,此时在test.c文件中声明一下g_val,就可以运行了。 全局变量是具有外部链接属性的,在其他源文件内部,只要适当地申明就可以使用。 当我们用static去修饰这个全局变量的时候,它就会报错(无法解析的外部符号),这是因为static修饰的全局变量的外部链接属性消失了,而变成了内部链接属性,只能在自己的.c文件内部使用,其他.c文件内部无法使用。所以本质上是影响了变量的作用域范围
3.修饰函数 static 修饰函数与修饰全局变量类似 新建一个add源文件,在add源文件中写入一个简单的Add求和函数,函数和全局变量一样也是具有外部链接属性的。
int Add(int x, int y)
{
return c+y;
}
extern int Add(int , int);
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
static修饰函数后,函数的外部链接属性就变成了内部链接属性,被static修饰的函数只能在自己的.c文件内部使用,其他.c文件内部无法使用,本质上影响了作用域范围。
static int Add(int x, int y)
{
return c+y;
}
extern int Add(int , int);
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
类型:
union、enum、struct、char、short、int、float、long、double、const、void、sizeof、signed、unsigned、typedef
关键字typedef —类型重命名
#include<stdio.h>
typedef unsigned int uint;
int main()
{
unsigned int num1 = 100;
unit num2 = 200;
return 0;
}
十三、define定义的常量和宏
1.定义常量
可以使用#define 定义一个标识符来表示一个常量 注:由define定义的常量只能在定义的地方做修改,其他处无法被修改。
格式:#define 标识符 常量值
#include<stdio.h>
#define MAX 10000
#define char_str "Hello,world"
int main()
{
printf("%d",MAX);
printf("%s",char_str);
return 0;
}
2.定义宏
也可以使用#define来定义宏
#include<stdio.h>
#define max(x,y) ((x)>(y)?(x):(y))
int main()
{
int a = 10;
int b = 20;
int m = max(a,b);
printf("%d",m);
return 0;
}
十四、指针
在学习指针之前,我们首先得认识认识一下内存。
内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。 所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。 为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。
假设有一栋楼,该楼共有六层,共有三十层房间,在没有门牌号的情况下,如何精准地定位找到自己想去的房间?不好寻找。而在实际生活中,每个房间都有门牌号,这让我们直接就可以找到自己想去的房间,而不至于那么麻烦。
而在内存中,内存中的每一个内存单元 相当于实际生活中的每一个房间,每一个内存单元也有对应的一个编号,而通过这个编号,我们也能快速找到这样一个个小的内存单元,这一个个内存单元的编号被称为地址,也叫做指针。 所以我们有这样一概念( 编号 = 地址 = 指针)。 我们想一下,1个内存单元给多大比较合适呢? 1个字节! 为什么要1个字节,而不是1bit、1KB……
如果用char类型来说,如果内存单元为1bit的话,需要8个bit的内存空间,而int类型则需要4*8=32个内存空间,显然,用bit多余了,1KB又太大,而1个字节恰恰合适。 基本的数据类型char类型占1个字节,int类型占4个字节。所以每个内存单元的单位以1个字节最合适。
那么内存单元的编号(地址)是怎么产生的呢?
在32位机器上,有32根地址线(物理电线),电线是通电的,通电之后就有高电平和低电平之分,电信号最终会转换成数字信号,而高电平转换成数字信号为数字“1”,低电平转换成数字信号为数字“0”,由此会产生32个0或者1的随机数字信号,就会组成232个二进制序列,这些组成不同的二进制序列就可以作为内存单元的编号,也就会产生232个地址。
那么232个地址就能管理232个字节的空间,即4294967296个byte, 4294967296byte/1024 = 4194304KB; 4194304KB/1024 = 4096MB; 4096MB/1024 = 4GB; 所以,232个地址最多也就占用4GB的大小内存。
int a = 10,本质就是在内存中申请4个字节大小的空间来存储10。
如何取到变量a的地址呢? 用&a(&为取地址操作符)表示变量a的地址。 注:a实际占用4个字节的空间,每个字节都有地址,但是&a拿到的是第一个字节的地址编号(也是最小的地址,如图中:0x0012ff40);
&a拿出的是地址,地址也是一个值,如何来存储&a呢,用int* pa = &a来存放地址,此时的pa是一个存放地址(指针)的变量,故pa被称为指针变量 那么pa仅仅是用来存储地址的吗?其实不然,我们可以通过pa来找到a,用*pa来表示。(此时的*为解引用操作符)
#include <stdio.h>
int main()
{
int a = 10;
int* pa = &a;
printf("%p\n",&a);
printf("%d\n",a);
*pa = 20;
printf("%d\n",a);
return 0;
}
除了整型类型的指针之外,其他类型如字符类型的指针,例子如下:
#include <stdio.h>
int main()
{
char ch = 'A';
char* pc = &ch;
*pc = 'q';
printf("%c\n", ch);
return 0;
}
指针变量的大小是多大呢?
指针变量是用来存放地址的,地址在32位机器上,是由32个0或1组成的二进制序列号,故需要32个比特位的空间存储,指针变量就需要四个字节,不论什么数据类型的指针变量,大小都是4个字节。 在64位机器上,是由64个0或者1组成的二进制序列号,需要64个比特位的空间存储,指针变量的大小就是8个字节。
结论:指针大小在32位平台是4个字节,64位平台是8个字节
我们也可以通过sizeof来计算指针变量的大小
#include <stdio.h>
int main()
{
int* pa;
char* ch;
double* pd;
printf("%d\n", sizeof(pa));
printf("%d\n", sizeof(ch));
printf("%d\n", sizeof(pd));
return 0;
}
十五、结构体
结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型。 比如描述学生,学生包含: 名字+年龄+性别+学号 这几项信息。 描述复杂对象,不能简单的使用单个的内置类型来描述了,这里只能使用结构体来描述。 例如:
struct Student
{
char name[20];
int age;
char sex[5];
char id[15];
};
结构体的初始化:
int main()
{
struct Student s1 = {"张三",18,"男","12345678"};
printf("%s %d %s %s\n",s1.name,s1.age,s1.sex,s1.id);
struct Student * ps = &s1;
printf("%s %d %s %s\n",(*ps).name,(*ps).age,(*ps).sex,(*ps).id);
printf("%s %d %s %s\n",ps->name,ps->age,ps->sex,ps->id);
return 0;
}
/*以上为初步学习C语言知识部分(点到为止不做深度解读),已完结 。*/
|