C语言复习笔记

4/12/2021 CC++

# 指针

  • 指针存放的是其他对象的内存地址,指针变量可以被赋值,即该指针可以指向其他对象,但不能指向其他数据类型的对象
  • & 出现在变量名前时是取地址符,可以获取到该变量的内存地址
  • 同时,& 也可以用来表示声明引用变量,引用通常用于函数参数列表和函数返回值
  • 在定义变量时,可以使用 * 来说明声明的变量为指针变量
  • 但是在语句中,* 是间接寻址运算符,* 在变量前表示取出该内存单元的值

# 数组

  • 数组和指针关系很密切:
//doubleAarra是一个指向&doubleAarray[0]的指针
double doubleAarray[50];
  • 使用数组名作为常量指针也是合法的
double doubleAarray[50];
double d = *(doubleAarray + 4); //这种用法是合法的
  • C/C++ 对 char 型数组做了特殊规定,直接输出首地址时,会输出数组内容。如果想得到地址,可采用 &
char name[] = {"Hello World"};
cout << name << endl; // 输出 Hello World
cout << &name << endl; // 输出 0x7ffe08e50977 

# 字符串

  • 字符串实际上是使用 null 字符 \0 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。
char hello[6] = {'H','e','l','l','o','\0'};
//编译器会在初始化数组时,自动把 \0 放在字符串的末尾,所以这两条语句基本等价
char hello[] = "Hello";

# C 库函数 gets()

  • char *gets(char *str) 从标准输入 stdin 读取一行,并把它存储在 str 所指向的字符串中。当读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
//函数声明
char *gets(char *str)
  • 参数: str 这是指向一个字符数组的指针,该数组存储了 C 字符串。
//用法
#include <stdio.h>

int main()
{
  char str[10];
  printf("请输入一个字符串:");
  gets(str);
  printf("您输入的字符串是:%s", str);
  return(0);
}
  • 实际运行会报错:warning: this program uses gets(), which is unsafe.
  • ⚠️ 危险:任何时候均要避免使用该函数,因为gets()这个函数只有一个参数,那就是字符缓冲区的指针,并没有指定该缓冲区的长度也就是大小。当你输入一个很长很长的字符串的时候,gets()函数会把每一个字符都存入到栈(statck)中,因此当字符串很大的时候就会导致程序异常终止。

# C 库函数 puts()

  • int puts(const char *str) 把一个字符串写入到标准输出 stdout,直到空字符,但不包括空字符。换行符会被追加到输出中。
//函数声明
int puts(const char *str)
  • 参数:str 这是要被写入的 C 字符串。
//用法
#include <stdio.h>
#include <string.h>

int main()
{
  char str1[15];
  char str2[15];

  strcpy(str1, "RUNOOB1");
  strcpy(str2, "RUNOOB2");

  puts(str1);
  puts(str2);
  
  return(0);
}

# C 库函数 scanf()

  • int scanf(const char *format, ...) 从标准输入 stdin 读取格式化输入。
//函数声明
int scanf(const char *format, ...)
  • 参数:format 是 C 字符串,包含了以下各项中的一个或多个:空格字符、非空格字符 和 format 说明符。
//用法
char a,b,c;
printf("请输入三个字符:");
scanf("%c%c%c", &a,&b,&c); 
printf("%c,%c,%c\n", a,b,c);

# 宏「#define 预处理」

  • 指令形式
#define macro-name replacement-text 
  • 宏可以带参数,例如:
#define MIN(a,b) (a<b ? a : b)
  • 宏定义不是C语句
  • 宏定义是用宏名代替一个字符串,也就是作简单的置换,不作正确性检查。
  • # 运算符会把 replacement-text 令牌转换为用引号引起来的字符串,例如:
#define REPLACE( x ) #x

cout << REPLACE(HELLO C++) << endl;

/**编译后如下**/

cout << "HELLO C++" << endl;

  • ## 运算符会把参数会被连接起来,并用来取代宏。
#define LINK(x,y)   x 
## y

cout << LINK(a,b) << endl;

/**编译后如下**/

cout << ab << endl;

  • 还有一些C++提供的预定义宏
cout << "__LINE__ : " << __LINE__ << endl;//编译时包含当前行号
cout << "__FILE__ : " << __FILE__ << endl;//编译时包含当前文件名
cout << "__DATE__ : " << __DATE__ << endl;//包含一个形式为 month/day/year 的字符串,显示编译时的日期
cout << "__TIME__ : " << __TIME__ << endl;//包含一个形式为 hour:minute:second 的字符串,它表示程序被编译的时间
  • 运行结果
__LINE__ : 45
__FILE__ : Class_test.cpp
__DATE__ : Apr 15 2021
__TIME__ : 00:46:54

# 结构体

  • 定义结构体
  • 为了定义结构,您必须使用 struct 语句。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下
// 「struct」「结构体名称」
struct Books {
member_type1 member_name1; //「成员类型」「成员名」
member_type2 member_name2; //「成员类型」「成员名」
char title[50]; //「成员类型」「成员名」
} Book1; //「结构变量名」此处可以指定一个或多个结构变量
  • 访问结构体成员,可以使用成员访问运算符 「.
  • 也可以定义指向结构体变量的指针
struct Books *struct_pointer;
  • 使用 「->」 运算符可以使用结构指针访问成员变量
strcpy( Book1.title, "ccc");
struct_pointer = &Book1;
char *t = struct_pointer->title;
cout<<t<<endl; //输出: ccc
  • typedef 关键字可以为创建的类型取一个别名
typedef struct Books {
member_type1 member_name1; //「成员类型」「成员名」
member_type2 member_name2; //「成员类型」「成员名」
char title[50]; //「成员类型」「成员名」
} Books; 

//可以直接使用 Books 来定义 Books 类型的变量,而不需要使用 struct 关键字
Books Book1 Book2;

TIP

printf() 语句中, %5.2f表示总长度为5个字符「.也占1字符」,小数点后保留两位的浮点数