【C】初识C语言(下)

简介: c语言入门内容讲解



1. 数组

要存储1-10的数字,怎么存储?

1.1 数组定义

C语言中给了数组的定义:一组相同类型元素的集合

int arr[10]                                                   =           { 1,2,3,4,5,6,7,8,9,10};
//定义一个整形数组,最多放10个元素                      //数组的初始化
int arr[10] = {1,2,3};//不完全初始化,剩余的值为0
int arr[  ] ={1,2,3};//不指定大小时,根据后面初始化的值输出
int arr[  ] //这种写法是完全错误的,不指定大小必须进行初始化
int arr[10]//随机值
int main()
{
        int n = 10;
        int arr[n];//c99 允许数组在创建的时候用变量指定数组大小,但是这种数组不能初始化
        return 0;
}

image.gif

1.2 数组的下标

C语言规定:数组的每个元素都有一个下标,下标是从0开始的。

数组可以通过下标来访问的。

比如:

image.gif

1.3 数组的使用

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

image.gif

2. 操作符

c语言是非常灵活的,就是因为操作符多

简单介绍为主,后面课件重点讲。

.1 算术操作符

+     -      *      /      %        前面三个和数学中基本一样,这里介绍一下后两个

#include<stdio.h>
int main() {
    printf("%d\n", 7 / 2);//3
    printf("%lf\n", 7 / 2.0);//3.50000
    printf("%.1lf\n", 7.0 /2);//3.5
    return 0;
}

image.gif

int main() {
    printf("%d\n", 7 % 2);//7/2=3……1
    printf("%d\n", 8 % 2);//……0
}

image.gif

2.2 移位操作符

>>         <<        向右向左移动二进制位

                         这里涉及二进制的计算和存储,暂时不作介绍

2.3 位操作符

&按位与      

^按位异或        

|按位或

2.4 赋值操作符

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

int main() {
  int a = 10;//这就是赋值操作符
  a = a + 5;
  a += 5;
  return 0;
}

image.gif

如上a +=5;等价于a =a+5;        后面的 -=         *=         /= 与之类似

2.5 单目操作符  

,只有一个数的操作符

!           逻辑反操作

-           负值

+           正值

&           取地址

sizeof      操作数的类型长度(以字节为单位)

~           对一个数的二进制按位取反

--          前置、后置--

++          前置、后置++

*           间接访问操作符(解引用操作符)

(类型)       强制类型转换

这里首先介绍一下c语言中如何表示真假以便以下代码片段的理解:
0表示假
非0表示真

2.51 单目操作符(非)!

int main() {            //       
    int a = 0;          //    
    scanf("%d",&a);     //    1
    printf("%d\n", a);  //    1
    printf("%d\n", !a); //    0    //只有一个操作数a
}

image.gif

c语言语法规定:当假变为真时输出固定值1,假一直为0,手动输入任何非0值都输出真

 

int main() {
  int flag = 0;
  if (flag)//flag为真,打印hehe
  {
    printf("hehe\n");
  }
  if (!flag)//flag为假打印haha
  { 
    printf("haha\n");
  }
  return 0;
}

image.gif

2.52 单目操作符 -        +

int main()
{
  int a = -10;
  int b = -a;    //通过-改变了a的符号
  printf("%d\n", b);
}

image.gif

int c = +a;
  printf("%d\n", c);//这样输出无法改变a的正负

image.gif

所以‘+’一般基本不用

2.53 单目操作符++ 和  --

image.gif编辑

后面所附数字是输出结果

2.6 关系操作符

>

>=

<

<=

!=   用于测试不相等

==      用于测试相等

2.7 逻辑操作符

&&     逻辑与

||          逻辑或

image.gif编辑

需要注意下面绿色的写法是错误的

image.gif编辑

2.8 条件操作符

exp1 ? exp2 : exp3    解析如下:

exp1         ?                         exp2                 : exp3                

表达式       判断真假           真执行                假执行

image.gif编辑

如图,若a>b为真,则输出a的值

          若a>b为假,则输出b的值

2.9 逗号表达式 下标引用、函数调用和结构成员

exp1, exp2, exp3, …expN

按顺序执行,结束出结果

int main()
{
  int a = 3;
  int b = 0;
  int c = 4;
  int d = (a=b-3,b=a+c,c=a-b,a=c+3);
          //a=-3 b=1   c=-4  a=-1
  printf("%d\n", d);
  return 0;
}
image.gif

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

[]                  ()                    . ->   结构体中使用,后期介绍

image.gif编辑

image.gif

3. 常见关键字

下表列出了 C 中的关键字。这些关键字不能作为常量名、变量名或其他标识符名称。

关键字 说明
auto 声明自动变量
break 跳出当前循环
case 开关语句分支
char 声明字符型变量或函数返回值类型
const 声明只读变量
continue 结束当前循环,开始下一轮循环
default 开关语句中的"其它"分支
do 循环语句的循环体
double 声明双精度浮点型变量或函数返回值类型
else 条件语句否定分支(与 if 连用)
enum 声明枚举类型
extern 声明变量或函数是在其它文件或本文件的其他位置定义
float 声明浮点型变量或函数返回值类型
for 一种循环语句
goto 无条件跳转语句
if 条件语句
int 声明整型变量或函数
long 声明长整型变量或函数返回值类型
register 声明寄存器变量
return 子程序返回语句(可以带参数,也可不带参数)
short 声明短整型变量或函数
signed 声明有符号类型变量或函数
sizeof 计算数据类型或变量长度(即所占字节数)
static 声明静态变量
struct 声明结构体类型
switch 用于开关语句
typedef 用以给数据类型取别名
unsigned 声明无符号类型变量或函数
union 声明共用体类型
void 声明函数无返回值或无参数,声明无类型指针
volatile 说明变量在程序执行中可被隐含地改变
while 循环语句的循环条件

3.1sizeof 操作符

sizeof 计算的结果单位是字节
sizeof不是函数,是操作符

int main()
{
  int a = 10;
  printf("%d\n", sizeof(a));//4
  printf("%d\n", sizeof a );//4
  printf("%d\n", sizeof(int));//4
  return 0;
}
image.gif
int main()
{
  int arr[10] = { 0 };
  printf("%d\n", sizeof(arr));//40,计算的是数组的总大小,单位是字节
  printf("%d\n", sizeof(arr[0]));//4
  printf("%d\n", sizeof(arr) / sizeof(arr[0]));//40 /4=10
  //数组的元素个数如何计算
  int sz = sizeof(arr) / sizeof(arr[0]);
  return 0;
}

3.2区分sizeof和strlen

#include <string.h>
int main() {
  char arr1[] = "abc";
  char arr2[] = { 'a', 'b','c' };
  printf("%d\n", strlen(arr1));
  printf("%d\n", strlen(arr2));
  printf("%d\n", sizeof(arr1));
  printf("%d\n", sizeof(arr2));
  return 0;
}
image.gif

输出结果如下:

image.gif编辑

strlen  是库函数        是求字符长度的,关注的是字符串中是否有\0,统计\0之前出现的字符个数

sizeof  是操作符        只关注占据了多大的内存空间,不关注内存中存放的数据      

sizeof 返回的单位是字节

3.3关键字 typedef

typedef 顾名思义是类型定义,这里应该理解为类型重命名。

比如:

//unsigned int 重命名为uint, 所以uint也是一个类型名

typedef unsigned int uint;

int main()

{

  //观察num1num2,这两个变量的类型是一样的

  unsigned int num1 = 0;

  uint num2 = 0;

  return 0;

}


register 寄存器关键字,起一个建议的作用,可以加快处理的速度,但由于计算机的发展,会自行识别重要与否,从而决定

image.gif编辑


3.4关键字static

C语言中:

static是用来修饰变量和函数的

1. 修饰局部变量-称为静态局部变量

2. 修饰全局变量-称为静态全局变量

3. 修饰函数-称为静态函数

3.4.1 修饰局部变量

//代码1
#include <stdio.h>
void test()
{
   int i = 0;
   i++;
   printf("%d ", i);
}
int main()
{
int i = 0;
   for(i=0; i<10; i++)
  {
       test();
  }
   return 0;
}
//代码2
#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;
}

image.gif

如下图

image.gif编辑

image.gif编辑

对比代码1和代码2的效果理解static修饰局部变量的意义。

输出结果如图 对比理解static修饰局部变量的意义。

结论:

static修饰局部变量改变了变量的生命周期

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

static修饰局部变量的时候,改变了变量的存储类型

普通的变量是存储在栈区的,被static修饰的变量是存储在静态区的

存储在静态区的变量,除了作用域不会销毁,依然存在

静态变量的生命周期就是程序的生命周期,程序结束的时候静态变量才回收空间

static修饰局部变量改变了变量的生命周期

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

3.4.2 修饰全局变量

//代码1
//add.c
int g_val = 2018;
//test.c
int main()
{
    printf("%d\n", g_val);
    return 0; }
//代码2
//add.c
static int g_val = 2018;
//test.c
int main()
{
    printf("%d\n", g_val);
    return 0; }

image.gif

image.gif编辑

代码1正常,代码2在编译的时候会出现连接性错误。

结论:

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

用。

全局变量是具有外部链接属性的,static修饰全局变量的时候,这个全局变量的外部连接属性就变成了内部连接属性,这个全局变量只能在自己所在的.c文件中看到,其他源文件无法使用

 

12.4.3 修饰函数

//代码1
//add.c
int Add(int x, int y)
{
   return c+y;
}
//test.c
int main()
{
   printf("%d\n", Add(2, 3));
   return 0;
//代码2
//add.c
static int Add(int x, int y)
{
   return c+y;
}
//test.c
int main()
{
   printf("%d\n", Add(2, 3));
   return 0;

image.gif

代码1正常,代码2在编译的时候会出现连接性错误.

结论:

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

剩余关键字后续课程中陆续会讲解。

4. #define 预处理指令  定义常量和宏        

    #include也称为预处理指令

代码演示如下:

//define定义标识符常量

#define MAX 1000      //        MAX   的值就是1000

//define定义宏,宏是有参数,和函数很像

#define ADD(x, y) ((x)+(y))//后面括号的是内容

#include  

int main()

{

  int sum = ADD(2, 3);

  printf("sum = %d\n", sum);

 

  sum = 10*ADD(2, 3);//宏会直接替换上面的(2)+(3))  而函数则需要调用

  printf("sum = %d\n", sum);

 

  return 0;

这里需要注意一下函数和宏的区别

image.gif编辑

宏和函数各有优缺点,具体暂时不谈

5.C 指针

学习 C 语言的指针既简单又有趣。通过指针,可以简化一些 C 编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。所以,想要成为一名优秀的 C 程序员,学习指针是很有必要的。

正如您所知道的,每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。请看下面的实例,它将输出定义的变量地址:

1

2

3

4

5

6

7

8

9

10

11

12

#include <stdio.h>

intmain ()

{

   int  var1;

   charvar2[10];

   printf("var1 变量的地址: %p\n", &var1  );

   printf("var2 变量的地址: %p\n", &var2  );

   return0;

}

当上面的代码被编译和执行时,它会产生下列结果:

1

2

var1 变量的地址: 0x7fff5cc109d4

var2 变量的地址: 0x7fff5cc109de

    • 什么是指针?

    指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:

    1

    type *var-name;

    在这里,type 是指针的基类型,它必须是一个有效的 C 数据类型,var-name 是指针变量的名称。用来声明指针的星号 * 与乘法中使用的星号是相同的。但是,在这个语句中,星号是用来指定一个变量是指针。以下是有效的指针声明:

    1

    2

    3

    4

    int    *ip;    /* 一个整型的指针 */

    double*dp;    /* 一个 double 型的指针 */

    float  *fp;    /* 一个浮点型的指针 */

    char   *ch;     /* 一个字符型的指针 */

    所有实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,对应指针的值的类型都是一样的,都是一个代表内存地址的长的十六进制数。

    不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。

      • 如何使用指针?

      使用指针时会频繁进行以下几个操作:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。这些是通过使用一元运算符 ***** 来返回位于操作数所指定地址的变量的值。下面的实例涉及到了这些操作:

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      #include <stdio.h>

      intmain ()

      //变量var是创建在内存中的(在内存中分配空间的),每个内存单元都有地址,所以变量也是有地址的。

      {

         int  var = 20;   /* 实际变量的声明 */     //var向内存申请4个字节的空间

         int  *ip;        /* 指针变量ip  的声明 */指针变量是用来存放地址的

         ip = &var;  /* 在指针变量中存储 var 的地址 */ip的类型根据var的类型进行声明

                                            //&var;     //取出a的地址,

              // 注:这里a的4个字节,每个字节都有地址,取出的是第一个字节的地址(较小的地址)

         printf("Address of var variable: %p\n", &var  );//打印地址,%p是以地址的形式打印

         /* 在指针变量中存储var的地址 */

         printf("Address stored in ip variable: %p\n", ip );

         /* 使用指针访问值 */

         printf("Value of *ip variable: %d\n", *ip );

         return0;

      }

      当上面的代码被编译和执行时,它会产生下列结果:

      1

      2

      3

      Address of var variable: bffd8b3c

      Address stored in ip variable: bffd8b3c

      Value of *ip variable: 20

      image.gif编辑

      指针本质是地址,口头语中指的是指针变量(上面代码中的ip

      int main()
      {
          int a = 10;
          int* pa = &a;//& 取地址操作符
          *pa = 20;//* 解引用操作
          printf("%d\n", a);
          return 0;
      }

      image.gif

      //要想知道指针变量有多大?

      //指针变量存储的是什么? - 地址

      //地址的存储需要多大空间,指针变量的大小就是多大

      int main()
      {
          printf("%zu\n", sizeof(char*));//zu专门用来打印sizeof返回值
          printf("%zu\n", sizeof(short*));
          printf("%zu\n", sizeof(int*));
          printf("%zu\n", sizeof(long*));
          printf("%zu\n", sizeof(float*));
          printf("%zu\n", sizeof(double*));
          return 0;
      }

      image.gif

      //32位机器 - 一个地址是32个二进制位,存储需要32个bit位的空间,所32位机器上,指针变量的大小是4个字节

      //64位机器 - 一个地址是64个二进制位,存储需要64个bit位的空间,所64位机器上,指针变量的大小是8个字节

      //取决于编出程序的大小

        • 内存

        内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。

        所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节

        为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地

        image.gif编辑

        6. 结构体

        结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型。

        比如描述学生,学生包含: 名字+年龄+性别+学号 这几项信息。

        这里只能使用结构体来描述了。

        例如:

        struct Stu
        {
           char name[20];//名字
           int age;      //年龄
           char sex[5];  //性别
           char id[15]; //学号
        };

        image.gif

        结构体的初始化:

        //打印结构体信息
        struct Stu s = {"张三", 20, "男", "20120101"};
        //.为结构成员访问操作符
        printf("name = %s age = %d sex = %s id = %s\n", s.name, s.age, s.sex, s.id);
        //结构体变量.结构体成员
        //->操作符
        struct Stu *ps = &s;
        printf("name = %s age = %d sex = %s id = %s\n", ps->name, ps->age, ps->sex, ps-
        >id);

        image.gif

        image.gif编辑

        相关文章
        |
        7月前
        |
        Java 编译器 程序员
        C语言 (3)
        C语言 (3)
        47 0
        |
        存储 Java 数据库
        |
        7月前
        |
        程序员 C语言
        C语言
        C语言
        45 0
        |
        2月前
        |
        Unix 程序员 C语言
        初识C语言
        C语言源于1972年,由贝尔实验室的丹尼斯·里奇和肯·汤普逊在开发UNIX操作系统过程中设计。它基于B语言改进而成,旨在成为一种实用的编程工具。尽管许多语言追求教育或易用性目标,但专为程序员设计的C语言,如今已成为主流编程语言之一。
        29 8
        |
        4月前
        |
        C语言
        C语言中的复合语句
        C语言中的复合语句
        525 1
        |
        5月前
        |
        Java 编译器 C#
        【C语言】初识C语言
        学习C语言前期需要掌握的一些基础知识
        62 2
        【C语言】初识C语言
        |
        7月前
        |
        Java Linux 编译器
        认识C语言
        认识C语言
        44 0
        |
        C语言
        C语言中的坑(1)
        C语言中的坑(1)
        53 0
        |
        算法 Serverless C语言
        C语言假期作业 DAY 08
        C语言假期作业 DAY 08
        |
        7月前
        |
        存储 C语言
        C语言中的&和*
        C语言中的&和*
        106 0