11.11大促主会场
新人页面
精选商品
首月0月租体验,领12个月京东PLUS
自营热卖

01初识C语言

凡夫俗子 6月前   阅读数 58 0

这篇博客将带大家初步认识C语言,由于仅仅是初步认识,因此具体内容并没有进行深度的说明讲解,具体更详细的内容将在之后的博客中单独讲解。


什么是C语言

C语言的定义百度不难获取。C语言是一门通用计算机编程语言,广泛应用于底层开发。那什么是计算机编程语言和底层开发呢?

什么是计算机编程语言

计算机语言顾名思义就是人和计算机交流的语言,即人给计算机发送指令,计算机读懂以后按照指令执行我们想要计算机执行的工作。常用的计算机语言有C/C++/JAVA等等。

什么是底层开发

我们常用的电脑(硬件),要让电脑工作就必须要给电脑装一个操作系统,比如win10,linux等,来进行对硬件的操作。操作系统和硬件由驱动层相关联。因此,硬件、驱动和操作系统就叫做底层,所以我们写一个操作系统、驱动软件等这些操作就叫做底层开发

在底层往上就是应用层,即我们能直观感受到的东西,比如应用软件(QQ、微信等)。C语言也可以用于应用软件开发,但是相比其他语言就显得很劣势。
在这里插入图片描述

计算机语言的发展过程

最初的编程语言我们称为机器语言,即二进制的语言,要想实现某一个功能就要写好多二进制的序列。
由于太难理解后来出现了汇编语言,汇编语言用助记符代替机器指令的操作码,我们用助记符就可以更加容易写代码。
后来发展出了更加容易的B语言和C语言,更加贴近我们人的逻辑。但后来由于C语言的标准不统一,这就导致A公司的代码在B公司上就无法运行,因此制定了ANSI C,即C语言国际标准。这些标准约束了C语言的语法规则

什么是编译器

主要的编译器有GCC,MSVC等,编译器就是编译代码的工具,用来将我们写的C代码转换成电脑能读懂的二进制
值得一提的是,我们常用的VS2019,Dev C++严格来讲并不能称为编译器,它们是由编译器组成的集成式开发环境。

ASCII码表

由于计算机中只有二进制数字,一些符号没法表示,例如,像a、b、c、d这样的52个字母(包括大写)以及一些常用的符号(例如*、#、@等),因此约定一套编码来表示这些符号,这就是ASCII表。
在这里插入图片描述

第一个C语言程序

创建工程 以VS2019为例

首先创建项目,然后创建源文件。
在这里插入图片描述在这里插入图片描述在这里插入图片描述这样我们便创建了一个新的C语言文件,接下来就可以写代码了。


主函数

主函数是C语言的程序入口,程序开始执行的位置。一个源文件当中只能有一个主函数,要不然编译器就不知道从哪个入口开始执行了。
主函数代码为

int main()
{
     

   return 0;
}

int是函数返回值的类型,最常用的是整型
main是主函数的函数名
()是函数的参数,由于主函数一般情况下为无参,因此()里面的内容可以为空,
{}里面是主函数的内容
return 0;表示的是函数的返回值

函数的内容以后再做进一步讲解,在此只需要简单认识即可。

比如我们要在屏幕上输出打印“hello world”这一行语句,我们就可以运用打印函数printf,它的具体用法是printf(“要输出的内容”)。
但是printf是C语言提供的库函数,我们在使用之前得先打声招呼,即要引用库函数的头文件,即,#include<stdio.h>,stido翻译为标准输入输出。我们的输入和输出函数都在这个头文件里面,每次要使用这些函数都要引用这个头文件。
因此我们的代码就是下面这样的:

#include<stdio.h>
int main()
{
     
   printf("hello world");
   return 0;
}

运行的结果是这样的:
在这里插入图片描述如此一来,我们的第一个C语言程序就写好了。


数据类型

我们在对一件事物的描述需要各种各样的数据,比如价格、体重等描述就要用到整数、小数等数据类型。因此C语言中引入了这些类型

char      //字符数据类型,比如a、b、c、!等字符 
short      //短整型 用来描述范围更小的整数
int         //整形 用来描述整数 
long        //长整型 用来描述范围更大的整数 
long long   //更长的整形 用来描述范围更大的整数 
float       //单精度浮点数 用来描述小数
double      //双精度浮点数 比float精度更高

不同数据类型的大小

在计算不同数据类型大小之前首先要清楚计算机中的单位:

计算机中最小的单位为bit(比特),即存放一个1或者0的空间。计算机是一个硬件,通电后,可以识别电信号,0和1代表两种逻辑状态,1代表电路连通状态,0代表电路断开状态;存放一个0或者1的空间大小为1个比特位。

计算机在存储数据和执行指令的时候是以8个"比特"为单位的,通常又叫做"字节"。

一字节等于8比特。也就是说一个字节可以存储8个二进制(0或1)的数据

拿整型(整数)举例,通常整型的大小是4个字节,也就是32个比特位,因此如果要存储一个整型数据数字5,那么它的内存状态是这样的:
在这里插入图片描述

从右向左,每个1依次代表2^0, 2^1, 2^2,… …2^31,而5用二进制表示为 2^2 + 2^0

如果给5加上1变为6,由于二进制逢二进一,因此最末位变为0,倒数第二位变为1
在这里插入图片描述以上就是比特和字节的概念。


另外,字节往上还有更大的存储单位,具体如下:

1字节(Byte)=8位(bit)
1KB( Kilobyte,千字节)=1024B
1MB( Megabyte,兆字节)=1024KB
1GB( Gigabyte,吉字节,千兆)=1024MB
1TB( Trillionbyte,万亿字节,太字节)=1024GB
1PB( Petabyte,千万亿字节,拍字节)=1024TB
1EB( Exabyte,百亿亿字节,艾字节)=1024PB
1ZB(Zettabyte,十万亿亿字节,泽字节)=1024EB
1YB( Yottabyte,一亿亿亿字节,尧字节)=1024ZB
1BB( Brontobyte,千亿亿亿字节)=1024YB


我们可以用sizeof这一求大小的操作符来计算不同数据类型在内存中所占空间的大小,单位是字节
在这里插入图片描述

可以看出,不同的整形和浮点型所占空间大小是不同的。我们可以使用不同整形和浮点型,防止空间浪费。比如short型的二进制换算成十进制,可以表示的范围是-32768~32767,int范围是-2147483648 ~2147483647,因此在描述年龄等较小的数据时,选择short型可以很好地节约空间。单精度浮点数在机内占4个字节,双精度浮点数在机内占8个字节。单精度浮点数有效数字8位,双精度浮点数有效数字16位。在使用浮点型时也可以使用不同的类型来节约内存。

数据类型的输出格式

不同的数据类型有不同的输出格式

    %d-打印整形
    %c-打印字符
    %f-打印浮点型-小数
    %p-以地址形式打印
    %x-打印16进制数字
    %s-打印字符串

不同的类型可以用多种格式打印
比如

int main()
{
     
   int a=32;
   printf("%x",a);//结果为20
   return 0; 
}

%x是16进制输出,因此在打印输出时,会将a转换为16进制再进行输出。

变量、常量

顾名思义,常量就是不能改变的量,在生活中常量有很多,比如圆周率、身份号码等。
变量就是值可以改变的量,比如体重、年龄等。

定义变量的方法

在C语言中,我们一般用数据类型+变量名+赋值操作符(=)+变量的值这种形式来定义一个变量。比如我们要定义一个整形变量age,它的值为10,我们就可以用以下方法:

int age=10;//age值为10,但由于age是变量,因此age的值可以被重新赋值
age=11;//此时age的值变为11

同理要定义一个浮点型变量weight和字符型变量ch,也是如此:

float weight=45.5;
char ch='w';

特别说明一下:

在C语言中,=并不是我们数学中的等号,而是一个赋值操作符,int age=10意为,定义一个整形变量age,将10赋值给age,此时age的值就是10。这个过程我们称为给age赋初值,如果不给age赋初值,age将无法使用,因为编译器也不知道age的值是多少。

当然也可以先定义一个变量age,然后再给age赋初值,不用一步进行

int age=10;

int age;
age=10

以上两个操作是等价的。

而在C语言中,等号为‘==’,即两个赋值操作符。
另外,对于单个字符,一般用单引号‘ ’,比如‘a’,‘b’,对于字符串,一般使用双引号“ ”,比如“hello world”。

局部变量和全局变量

变量分为局部变量和全局变量:

全局变量:定义在代码块 ({})之外的变量
局部变量:定义在代码块 ({})之内的变量

int g=100;//全局变量

void test()//定义一个函数,以后会具体说明
{
     
  int b=100;//局部变量
}

int main()
{
     
   int a=10;//局部变量
   
   return 0;
} 

特别说明:

全局变量与局部变量名相同,局部变量优先。
虽然全局变量与局部变量名字可以相同,但是在写代码过程中不建议相同,因为会造成不必要的错误

int a=100;//全局变量
int main()
{
     
   int a=10;//局部变量
   printf("%d",a);// 局部变量优先,结果为10
   return 0;
} 

变量的作用域和生命周期

作用域

作用域(scope),程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用
的。限定这个名字的可用性的代码范围就是这个名字的作用域。
一句话来讲就是一个变量的可用的范围。

局部变量的作用域是变量所在的局部范围
全局变量的作用域是整个工程

举一个例子:

int b=20;
int main()
{
     
  int c=30;
  
   {
     
    int a=10;
   }
   printf("a=%d",a);//打印会报错 无法打印输出
   printf("b=%d",b);//可以打印输出

  {
     
         printf("c=%d",c);//可以打印输出
  }
   return 0;
}

a是局部变量,a的定义范围是a所在的那个{},它的作用域就是它所在的{},出了{}以后a就不能使用了。
b是全局变量,作用域是整个工程,因此b的作用域并不受{}的限制。
c的是局部变量,c的作用域是整个main函数所在的范围,由于 printf(“c=%d”,c);所在的{}也属于main函数所在的范围,因此可以打印输出。

生命周期

变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段。如果变量不销毁,那么每次我们运行都要开辟一块空间来存放我们的变量,那么我们的内存早就用完了,因此变量存在生命周期也是合情合理。

  1. 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
  2. 全局变量的生命周期是:整个程序的生命周期,即从程序开始到程序结束。

特别说明一点:

全局变量能够在不同源文件中使用,但要用extern声明其为外部变量

比如我们在要test中使用test1中的变量a
在这里插入图片描述
如果未使用extern声明则会报错
在这里插入图片描述
如果声明后则不会报错
在这里插入图片描述

常量

C语言中常量分为以下几种:

  • 字面常量
    程序中出现的数字,字符等。
#include<stdio.h>
int main()
{
     
	int a = 10;
	char b = 'w';

	return 0;
}

10和w就是字面常量。

  • const 修饰的常变量(无法修改的变量称为常变量)
int main()
{
     
	const int a = 10;

	return 0;
}

const修饰的常变量无法修改,比如下面的程序

#include<stdio.h>
int main()
{
     
	const int a = 10;
	a = 20;

	return 0;
}

在这里插入图片描述

虽然const修饰的变量无法修改,但它本身还是一个变量,具有变量的属性。我们可以通过a是否可以作为数组的大小来验证这一问题。

在这里插入图片描述
可以看出a此时还是一个变量。

  • #define 定义的标识符常量

这种定义方式相当于给字面常量起别名,它的别名具有字面常量的属性,在使用时别名直接替换为字面常量,比如下面的代码。

#include<stdio.h>
#define a 10
int main()
{
     
	int arr[a] = {
      0 };//相当于int arr[10] = { 0 };
	a=20;//无法修改,因为a具有字面常量的属性;
	return 0;
}

在这里插入图片描述

  • 枚举常量

通过枚举关键字enum定义的常量;

在此不作过多介绍

字符串+转义字符+注释

字符串

C语言中由双引号引起的一串字符叫做字符串。
注:字符串相当于多个字符连续存放在内存中,但是字符串的结尾是一个隐藏的 \0 转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串内容。
\0对于字符串非常重要,比如下面的代码:

int main()
{
     
    char arr1[] = "abc";
    char arr2[] = {
     'a', 'b', 'c'};
    char arr3[] = {
     'a', 'b', 'c''\0'};
    printf("%s\n", arr1);//abc
    printf("%s\n", arr2);//abc和乱码
    printf("%s\n", arr3);//abc
    return 0;
 }

在这里插入图片描述

从监视中不难看出arr1在结尾处比arr2多了一个\0,而arr1和arr3是一样的。
arr1字符串后面有一个隐藏的\0 ,因此在打印输出时,遇到\0后,打印停止。
arr2字符串后面没有\0,因此在打印完abc以后还会继续打印,直到遇到\0才会停止。
arr3字符串有\0,遇到\0后,打印停止。

转义字符

转义字符顾名思义就是转变原来含义的意思。比如每次我们在printf打印时加入一个换行符\n,程序输出完以后就会自动换行,而不是输出\n。

转义字符 释义
\? 在书写连续多个问号时使用,防止他们被解析成三字母词
\ ’ 用于表示字符常量’
\“ 用于表示一个字符串内部的双引号
\\ 用于表示一个反斜杠,防止它被解释为一个转义序列符。
\a 警告字符,蜂鸣
\b 退格符
\f 进纸符
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\ddd ddd表示1~3个八进制的数字
\xdd dd表示2个十六进制数字

比如下面的程序:

#include <stdio.h>
#include<string.h>
int main()
{
     
    // \32被解析成一个转义字符
    //\32 32是2个8进制数字
    //32作为8进制代表的十进制数字的ASCII码值对应的字符
    //100先转化为10进制为64,然后将64转化为ASCII码值代表的字符
    printf("%d\n", strlen("c:\test\100\test.c"));//结果为13
    return 0; 
    }

strlen这个函数可以求字符串的长度,在这里\t和\100都是一个字符,因此一共有13个字符,输出结果为13。\t是水平制表符算作一个字符可以理解,那为什么\100也是一个字符呢?
实际上\100属于上述转移字符中的 \ddd类型,100是一个八进制的数字,编译器先将100转化成十进制也就是64,在找到64从ASCII码表中代表的字符,\100就相当于那个字符。
在这里插入图片描述

补齐字符

int main()
{
     
	int a = 123;
	int b = 1;
	printf("%3d\n%3d\n", a, b);//%3d是右对齐,如果输出的位数不够三位,就会补空格
    printf("%3d\n%-3d\n", a, b);//%-3d是左对齐
}

结果是这样:
在这里插入图片描述

注释

  1. 代码中有不需要的代码可以直接删除,也可以注释掉
  2. 代码中有些代码比较难懂,可以加一下注释文字
    比如:
#include <stdio.h>
int Add(int x, int y) 
{
     
    return x+y; }
/* int Sub(int x, int y) { return x-y; } */
int main()
{
     
    //int a = 10;
    //调用Add函数,完成加法
    printf("%d\n", Add(1, 2));
    return 0;
 }

注释有两种风格:

  • C语言风格的注释 /xxxxxx/
    • 缺陷:不能嵌套注释
  • C++风格的注释 //xxxxxxxx
    • 可以注释一行也可以注释多行

选择语句

顾名思义,就是根据不同的条件选择性地执行不同的语句。比如下面的程序;

#include <stdio.h>
int main()
{
     
    int coding = 0;
    printf("1+1=?>");
    scanf("%d", &coding);
    if(coding == 2)
   {
     
       prinf("回答正确\n");
   }
    else
   {
     
       printf("回答错误\n");
   }
    return 0;
  }

如果if里面的条件成立,就会执行if语句里面的代码,如果不成立,则执行else里面的代码。

循环语句

当条件成立,就会不断执行循环语句中的内容,直到条件不成立,跳出循环。

C语言中实现循环的方式:

  • while语句
  • for语句
  • do … while语句

由于只是初识C语言,因此在这里只挑while循环来说明:

//while循环的实例
#include <stdio.h>
int main()
{
     
    int line = 0;
    while(line<20000)
   {
     
        line++;
        printf("hello world\n");
   }
    return 0;
 }

当line等于20000时,会跳出循环,因此屏幕上会打印20000行hello world。

函数

当一个动作(比如两个数相加,相减)不断执行的时候,我们就可以将这个动作写成一个函数,在需要执行这个动作的时候,只需调用函数就可以,以此来简化代码。比如一个加法的函数:

#include <stdio.h>
int Add(int x, int y)
{
     
  int z = x+y;
  return z;
 }
int main()
{
     
   int num1 = 0;
  int num2 = 0;
   int sum = 0;
   printf("输入两个操作数:>");
   scanf("%d %d", &num1, &num2);
   sum = Add(num1, num2);//将num1,num2的值传给函数中的x,y
   printf("sum = %d\n", sum);
   return 0; 
 }

由于是初识C语言,因此只需对函数进行简单的了解即可。

数组

数组就是一组相同类型元素的集合,用来存放多个相同类型的元素

数组的定义

int arr[10] = {
     1,2,3,4,5,6,7,8,9,10};//定义一个整形数组,最多放10个整形元素

int 是数组的类型;arr是数组的名字;[10]是数组的大小,数组的大小也可以不写,编译器会自动识别数组的大小;{ }内是数组的每个元素。

数组的使用

#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;
 }

强调一点:要访问数组的元素,就要用到数组的下标,比如arr[i]中,i就是数组的下标。数组下标是从0开始的整数,因此数组的第一个元素的下标元素为0而不是1。以此类推,第二个元素的下标为1,第三个元素下标为2 … …

操作符

顾名思义就是对变量进行操作的符号,比如加减乘除等,在此仅做简单的介绍。

算数操作符

+ - * / %   加 减 乘 除 取模(即求一个数除以另一个所得到的余数)

移位操作符

>> <<    左移和右移
  • 位移操作符移动的是变量的二进制位而不是十进制位

左移操作符<<将二进制位的位数向左移动,移动以后移出位丢弃,右边补0,比如将数字1进行左移一位。

int main()
{
     
    int a = 1;
    int b = a << 1;
    printf("%d", b);

    return 0;
}

在这里插入图片描述
在这里插入图片描述

右移运算是将一个数的二进制位的位数向右移动,移出位被丢弃,左边移出的空位或者一律补0,或者补符号位,这由不同的机器而定。

左移和右移并不会改变变量本身的大小。

在这里插入图片描述
a还是原来的a,本身的值并没有改变

位操作符

&  |  ^   与运算  或运算  异或运算

对二进制位进行运算;& 两个位都为1时,结果才为1,其余情况全为0;| 两个位都为0时,结果才为0,其余情况全为1;^ 两个位相同为0,相异为1

比如将5和3进行与运算:
在这里插入图片描述
在这里插入图片描述

赋值操作符

=   +=   -=    *=   /=    &=    ^=    |=      >>=      <<=

= 将右边的值赋值给左边
+=对原本的操作进行了简化, a+=1 等价于 a=a+1 只是a+=1更简便一些, 其他操作符也是同理

单目操作符

!           逻辑反操作(将真变为假,假变为真,非0的数都是真,0为假)
-           负值
+           正值
&           取地址(与指针配合使用)
sizeof      操作数的类型长度(求数组的大小,单位是字节)
~           对一个数的二进制按位取反
--          前置、后置--
++          前置、后置++
*           间接访问操作符(解引用操作符)
 (类型)       强制类型转换,将一个类型强制转换成另一个类型

这里单独说一下前置++和后置++,前置- -和后置- -也是同样的道理

++在前,先自加1,再使用
++在后,先使用,再自加1

在这里插入图片描述
a先自加1,再将自己的值赋值给b
在这里插入图片描述
a先将自己的值赋值给b,再自加1

关系操作符

>    //大于
>=    //大于等于
<     //小于
<=     //小于等于
!=    // “不相等”
==    //“相等”

逻辑操作符

&&        逻辑与   所有表达式都为真(非0),那整体就为真(1),否则为假(0||        逻辑或   所有表达式有一个为真(非0),那么整体就为真(1),只有所有表达式都为假时整体才为假(0

在这里插入图片描述

条件操作符(三目运算符)

exp1 ? exp2 : exp3    如果表达式1的值为真,整体的值就是表达式2,如果表达式1的值为假,整体的值就是表达式3

在这里插入图片描述

逗号表达式

exp1, exp2, exp3, …expN  每个表达式从左向右依次进行计算,
整个表达式的结果是最后一个表达式计算结束的结果
#include<stdio.h>
int main()
{
     
	int a = 1;
	int b = 3;
	a = (b = a + 1, a = b + 1,b= a + b);
	//先计算a+1的值然后将其赋值给b,此时b的值为2,a的值为1;
	//再计算b+1的值然后将其赋值给a,此时a的值为3,b的值为2;
	//最后计算a+b的值并将结果赋值给b,此时b的值为5
	//整体表达式的结果就是最后一个表达式的结果,最后一个表达式的结果为5,因此整体表达式结果为5
	printf("%d", a);
	return 0;
}

在这里插入图片描述

下标引用、函数调用和结构成员

[]    用来访问数组中的成员,如arr[1]就是访问数组的第二个成员(数组的下标从0开始)
()    用来调用函数时给函数传参
.     用来访问结构体成员
 ->   用来通过指针访问结构体成员

常见关键字

C语言内置的关键字。只需初步了解即可。另外记住,变量名不能和关键字相同,要不然编译器无法区分关键字和变量名。

auto--自动  局部变量都是自动变量 但在编译器auto省略
break--循环中停止循环 switch选择语句中结束语句
case--switch语句中进行选择
char
const--常变量   
continue--继续,运用在循环中 
default--默认,用在switch选择中使用 
do   
double 
else  --条件语句中使用
enum --枚举 
extern--引入外部负号
float--单精度浮点数
for   
goto  
if --条件语句中使用  
int   
long  
register--寄存器关键字,建议将变量定义为寄存器变量
return   
short  
signed--有符号数,
signed intint 等价
sizeof   
static--静态的 1.修饰局部变量,生命周期变长-静态局部变量 2.修饰全局变量,改变变量的作用域,使变量只能作用在自己所在的源文件使用,出了源文件将无法使用-静态全局变量 3.修饰函数,改变函数的链接属性,普通函数具有外部链接属性(外部文件想使用该函数只需声明即可),被static修饰后变成内部链接属性-静态函数
struct--结构体关键字  
switch  
typedef--类型定义--类型重定义(起别名)
unsigned int u_int
union--联合体(共用体)  
unsigned--无符号数
void  volatile  while
  • auto
    auto意为自动的,局部变量又叫自动变量,自动创建和销毁,局部变量前都有auto修饰,但省略不写;
  • signed
    意为有符号数,int 和 signed int 是等价的,int本身就是有符号整形
  • unsigned
    意为无符号数 ,unsigned int没有符号,也就意味着没有负数
  • typedef
    类型重定义
    给类型重新起名字,用于简化代码,具体用法为

typedef 原来的名字 新的名字

比如:

int main()
{
     
     typedef unsigned int u_int;
     unsigned int num1=20;
     u_int num2=20;//num1和num2等价
}
  • static关键字
    1.用来修饰局部变量,使其成为静态局部变量

static修饰局部变量改变了变量的生命周期,让静态局部变量出了作用域依然存在,到程序结束,
生命周期才结束。

比如下面的代码

#include <stdio.h>
void test()
{
     
    //static修饰局部变量
    static int i = 0;
    i++;
    printf("%d ", i);
}
int main()
{
     
 int i = 0;
    for(i=0; i<10; i++)
   {
     
        test();
   }
    return 0; }

结果为:
在这里插入图片描述

test函数中的局部变量i在test函数运行结束后并没有被销毁,每次调用test函数都会使i自增。

为了更清晰地对比,我们可以观察把static去掉以后程序的运行结果

#include <stdio.h>
void test()
{
     
	//static修饰局部变量
	int i = 0;
	i++;
	printf("%d ", i);
}
int main()
{
     
	int i = 0;
	for (i = 0; i < 10; i++)
	{
     
		test();
	}
	return 0;
}

在这里插入图片描述

  • static 修饰全局变量

一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使用。

我们在变量的作用域和生命周期那里已经了解到了,全局变量可以使用关键字extern从而使其能够在其他文件中被使用,但一旦被static修饰,则无法被使用

在这里插入图片描述
在这里插入图片描述

  • static修饰函数

一个函数被static修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用。

效果与static修饰全局变量类似

define定义常量和宏

具体方式

#defne 宏名(被替换的内容)(要替换的内容)

//define定义标识符常量
#define MAX 1000//在程序中,只要遇到MAX,都会被替换为1000
//define定义宏
#define ADD(x, y) ((x)+(y))
#include <stdio.h>
int main()
{
     
    printf("%d\n", MAX);
    int sum = ADD(2, 3);//会将2,3与宏中的x,y进行替换,因此ADD(2,3)就相当于((2)+(3))
    printf("sum = %d\n", sum);
    sum = 10*ADD(2, 3);//10*ADD(2,3)就相当于10*((2)+(3))
    printf("sum = %d\n", sum);
    return 0;
 }

在这里插入图片描述

指针

要理解指针,首先要理解内存。我们电脑的内存都被划分为很小的内存单元,并给每个内存单元都进行编号,这个编号就是内存的地址。那内存地址是如何产生的呢?

以32位举例,32位有32根地址线/数据线,地址线一旦通电就会有正电(1)和负电(0);通电后电信号转化为数字信号,因此有2^32 个二进制序列,将这些序列作为每个内存单元的编号,就会产生2^32个内存单元,每个内存单元的大小为一个字节

在这里插入图片描述
指针就是存储地址的一个变量,比如:

int num = 10;
int *p;//p为一个整形指针变量
p = &num;

&操作符可以将num的地址取出,然后赋值给指针p。
但我们知道num占四个字节,因此它有四个地址,&取出的是num的起始位置地址。

指针的使用实例:

#include <stdio.h>
int main()
{
     
 int num = 10;
 int *p = &num;
 *p = 20;//*是解引用操作符,*p是通过p找到p指向的对象,即num
    return 0;
}

*是解引用操作符,*p是通过p找到p指向的对象,即num

p也是一个指针变量,它也有地址。
在这里插入图片描述

指针的大小

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

可以得出结论:指针大小在32位平台是4个字节,64位平台是8个字节。

结构体

有的对象是非常复杂的,比如要表示一个人,他有名字、身高、体重等信息,想要描述这个人,仅仅使用单一的变量是很难做到的,因此结构体就是我们创造出来的一个类型,用来描述一个复杂的对象。比如要描述一个人:

struct Stu
{
     
    char name[20];//名字
    int age;      //年龄
    char sex[5];  //性别
    char id[15]//学号
};
int main()
{
     
struct Stu s = {
     "张三"20"男""20180101"};//创建一个学生s,并对其进行初始化赋值
//.为结构成员访问操作符,能够访问结构体的成员
printf("name = %s age = %d sex = %s id = %s\n", s.name, s.age, s.sex, s.id);
//创建一个结构体指针,用来存放s的地址
struct Stu *ps = &s;
//->操作符可以通过指针来访问到结构体的具体成员
printf("name = %s age = %d sex = %s id = %s\n", ps->name, ps->age, ps->sex, ps- >id);
}

我们通过结构体创建一个学生s,并对其进行初始化操作,此时我们可以通过点操作符.来访问结构体具体的成员,具体语法为:结构体变量名.结构体具体内容,比如s.name
我们也可以创建结构体指针来指向s,并通过箭头操作符->来通过结构体指针来访问结构体成员,具体语法为结构体指针->结构体内容,比如ps->name


总结:

这篇博客带大家了解了C语言的基本语法内容,对于刚刚入门的萌新来讲,相信这些内容会让其更加了解C语言。另外,这只是C语言的一点基础内容,更深入的内容我会在后续博客中展开讲解。
当然,这篇博客肯定还有可以完善的地方,如果有错误的地方请在评论区指正,非常感谢!另外,如果有更好的建议,也欢迎在评论区提出。我会进行博客的完善和修改。


注意:本文归作者所有,未经作者允许,不得转载

全部评论: 0

    我有话说: