初识C语言_Part 2(零基础超详解!)(一)

简介: 初识C语言_Part 2(零基础超详解!)

初识C语言 (2)


#1. 关键字


前言:C语言提供了丰富的关键字,这些关键字都是语言本身预先设定好的,用户自己是不能创造关键字的。


1.1static关键字


1.1.1 static修饰局部变量


我们来看下边一段示例代码:


void test()
{
  int a = 5;
  a++;
  printf("%d ", a);
}
int main()
{
  int i = 0;
  while (i < 10)
  {
  test();
  i++;
  }
  return 0;
}


这段代码会打印10个6,为什么呢?因为a这个变量是定义在test这个函数内部的,是个局部变量。每次调用test函数时,a变量会被重新创建并且被赋初始值为5,再经过++操作变成6被打印,当test函数调用完毕时,a这个局部变量又会被销毁。当下一次调用时,a又会被重新创建并被赋初始值为5,这样一直重复10次。


假若我们用static修饰a变量呢?


void test()
{
  static int a = 5;
  a++;
  printf("%d ", a);
}
int main()
{
  int i = 0;
  while (i < 10)
  {
  test();
  i++;
  }
  return 0;
}


此刻,就会在屏幕上打印6-15.


原因:被static修饰的局部变量,该变量的空间直到整个程序运行结束(main函数执行完毕)才会被销毁。当第一次调用test函数时,a被创建赋初始值为5,++之后变成6被打印,但是这次结束调用时,a变量的空间并不会被销毁,并且a的值为6,当第二次调用test函数时a的值仍然为6,并且a的地址不会发生变化,经过++操作之后,a变为7……以此重复10次。


注意:被static修饰的局部变量在编译阶段就被创建了。


但是为什么被static修饰之后,局部变量的空间就变得“长期有效”了呢?


解释:在c/c++中,内存空间被大致分为了三部分:


栈区:存放局部变量,形参,以及 具有临时作用的变量,栈区变量的特点是,进入作用域就创建,出了作用域就被销毁。

堆区:用于动态内存分配的(malloc,realloc,calloc)

静态区:存放全局变量,静态变量,静态区的变量的特点是:创建之后,直到程序结束才被销毁


所以:局部变量本来是存放在栈区的,但是被static修饰的局部变量就被放在了静态区了,static修饰局部变量,改变了变量的存储类型,使局部变量的生命周期变长了,但是作用域不变,直到程序结束才结束。


1.1.2 static修饰局部变量


我们在一个程序中创建两个源文件:


test1.c


int g_val = 10;


test2.c


#include<stdio.h>
extern int g_val;
int main()
{
  printf("%d", g_val);//打印10
  return 0;
}


假如test1.c中的g_val被static修饰呢?那么程序将报错无法运行。


因为:全局变量具有外部链接属性,所以可以在其他的源文件内使用。static修饰全局变量时,改变了全局变量的链接属性,由外部链接属性变成了内部链接属性。所谓内部链接属性,就是只能在自己内部源文件能看到。这个静态变量只能在自己的源文件内部使用,不能在其他的源文件内使用了 。


1.1.3 static修饰函数


test1.c


int Add(int x, int y)
{
  return x + y;
}


test2.c


extern int Add(int x, int y);
int main()
{
  int a = 10;
  int b = 10;
  int sum = Add(a, b);
  printf("%d", sum);//打印20
  return 0;
}

若Add函数被static修饰,那么该函数只能在该源文件内部使用。


因为:static修饰函数,函数本身也具有外部链接属性,被static修饰之后,就变成了内部链接属性。使得函数只能在自己所在的源文件内部使用,不能在其他文件内使用。


1.2.struct关键字


当我们想要用C语言描述一个学生时,单靠C语言本身的数据类型很难做到。C语言本身提供的类型有点单一,所以这时就可以自定义一个类型,可以用struct关键字来定义。例如:


struct Student
{
  char name[10];
  int age;
  char sex[5];
};


此时我们就创建了一个结构体类型,结构体中的name,age,sex称之为结构体成员。struct Student称为结构体类型,这个struct Student 是自定义类型,int是C语言自带的类型,他们的用法类似,都能创建变量。接下来我们利用struct Student 创建一个结构体变量。如下:


int main()
{
  struct Student student = { "张山",19,"男" };
    struct Student student1 = { "李四",17,"男" };
  return 0;
}


此时我们创建了学生student和student1,我们可以这样理解,struct Student就相当于是个房间设计图纸,通过这个图纸我们设计出很多房间。在创建结构体的同时,我们对结构体成员进行初始化。注意:初始化时要和结构体的成员相对应,例如:张山对应char name[10]; 19对应int age;男对应char sex[5];


那么我们如何访问这些结构体成员呢?这里就要提到之前的 . (结构体成员访问符),下面我们使用这个操作符打印一下结构体成员:


struct Student
{
  char name[10];
  int age;
  char sex[5];
};
int main()
{
  struct Student student = { "张山",19,"男" };
  struct Student student1 = { "李四",17,"男" };
  printf("%s %d %s", student.name, student.age, student.sex);//打印结果: 张山 19 男
  return 0;
}


1.3 typedef关键字


定义:typedef是类型重定义符号。可以为一个类型重命名。看示例代码:


注意:typedef是类型重定义,例如下边这段代码,被重定义之后的用法和重定义之前的用法是一样的。


unsigned long long a = 10;
int main()
{
  unsigned long long b = 20;
  printf("%d %d", a,b);
  return 0;
}


我们在写这段代码时,会发现unsigned long long这个类型名字很长,为了方便节省时间,我们通常对其进行类型重定义操作。例如:


typedef unsigned long long ull;//被重定义之后,ull也是一个类型名
unsigned long long a = 10;//这里a和b的类型是一样的
int main()
{
  ull b = 20;
  printf("%d %d", a,b);
  return 0;
}


改成这样就会方便很多。注意:typedef使用完之后要在语句之后加分号。(就像第一行这样,分号不能少)。


1.4 define定义常量和宏


1.4.1 define定义常量


我们看之前的文章举过的一个例子:


//编译失败 报错
int main()
{
  const int a = 10;
  int arr[a] = { 0 };
  return 0;
}

这段代码会报错,注意:数组的括号内必须是常量,因为被const修饰的变量本质上还是变量。那么这里提到的define关键字就可以定义真正的常量。请看代码:


这里特别注意:c99标准之前,数组的大小不能是变量。但在c99标准中引入了变长数组的概念,这时允许数组的大小是变量,但是不能直接被初始化,但是visual studio编译器不支持变长数组。但是有些编译器是支持的,例如:gcc编译器就支持c99中的变长数组。


注意:使用define时,前面的#不要忘了哟


//成功运行
#define MAX 100
int main()
{
  int arr[MAX] = { 0 };
  return 0;
}

这里的由#define定义的就是常量。#define不仅仅能定义数字,例如:


//成功运行
#define NAME "张山" //define定义字符串
int main()
{
  printf("%s", NAME);//注意以%s格式打印字符串
  return 0;
}


当然还能定义其他的类型,这里就不赘述了。


1.4.2 define定义宏


回忆一下之前讲过的函数部分,我们提到了Add函数,能完成两个数的相加,下面我们就用宏来实现类似的相乘的功能。


//语法格式 #define 宏名(宏参数)宏体
#define ADD(x,y) ((x)*(y))
int main()
{
  int a = 10;
  int b = 20;
  int sum = ADD(a+b, b);
  printf("%d", sum);
  return 0;
}


可以自己感受一下宏的用法,这里建议((x)*(y))这里分别给x和y的括号不要省略了,假若我们去掉,测试一下:


#define ADD(x,y) (x*y)
int main()
{
  int a = 10;
  int b = 20;
  int sum = ADD(a+b, b);
    //编译的时候会替换成: int sum = (a+b*b) 不是我们想要的运算顺序和运算结果
  printf("%d", sum);
  return 0;
}


我们会发现,这里就得不到我们想要的结果了,因为宏只是简单字面替换。


相关文章
|
C语言
初识C语言_Part 2(零基础超详解!)(二)
初识C语言_Part 2(零基础超详解!)
|
存储 编译器 C语言
初识C语言_Part 1(零基础超详解!)(二)
初识C语言_Part 1(零基础超详解!)
131 0
|
C语言
初识C语言_Part 1(零基础超详解!)(一)
初识C语言_Part 1(零基础超详解!)
105 0
|
1月前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
67 10
|
1月前
|
存储 程序员 C语言
【C语言】文件操作函数详解
C语言提供了一组标准库函数来处理文件操作,这些函数定义在 `<stdio.h>` 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
52 9
|
1月前
|
存储 Unix Serverless
【C语言】常用函数汇总表
本文总结了C语言中常用的函数,涵盖输入/输出、字符串操作、内存管理、数学运算、时间处理、文件操作及布尔类型等多个方面。每类函数均以表格形式列出其功能和使用示例,便于快速查阅和学习。通过综合示例代码,展示了这些函数的实际应用,帮助读者更好地理解和掌握C语言的基本功能和标准库函数的使用方法。感谢阅读,希望对你有所帮助!
42 8
|
1月前
|
C语言 开发者
【C语言】数学函数详解
在C语言中,数学函数是由标准库 `math.h` 提供的。使用这些函数时,需要包含 `#include <math.h>` 头文件。以下是一些常用的数学函数的详细讲解,包括函数原型、参数说明、返回值说明以及示例代码和表格汇总。
52 6
|
1月前
|
存储 C语言
【C语言】输入/输出函数详解
在C语言中,输入/输出操作是通过标准库函数来实现的。这些函数分为两类:标准输入输出函数和文件输入输出函数。
279 6
|
1月前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
64 6
|
1月前
|
C语言 开发者
【C语言】断言函数 -《深入解析C语言调试利器 !》
断言(assert)是一种调试工具,用于在程序运行时检查某些条件是否成立。如果条件不成立,断言会触发错误,并通常会终止程序的执行。断言有助于在开发和测试阶段捕捉逻辑错误。
43 5