本文介绍如何使用c语言
运行环境 vs2017,ctrl + F5 运行程序
目录
初识
常量和变量
标识符
数据类型
运算符
输入输出语句
流程控制语句
变量和函数的属性
指针
结构体
结构体在数据结构中的使用
共用体类型
typedef关键字的使用
文件操作
- 初识
- c程序基本结构
#include "stdafx.h" // 指定头文件,想使用函数库中的函数必须指明 int main() // 程序入口 { int a = 111, b = 222, sum; sum = a + b; printf("和是 %d\n", sum); // 输出语句,%d是十进制占位符 return 1; }
- c函数调用
int main() { int max(int x, int y); // 使用自定义函数之前,必须再定义一次 int a, b, c; scanf_s("%d和%d", &a, &b); // 收集用户输入的数据,&是地址符,表示将输入的数据传递给变量 c = max(a, b); printf("max=%d\n", c); return 0; } int max(int x, int y) { // 定义函数 int z; if (x > y) { z = x; } else { z = y; } return z; } 空参数的函数定义 int min(void) { return 0; } int min() {return 0;}
- c程序基本结构
- 常量和变量
- 常量
整型常量 1000 实型常量 12.34 12.34e2 字符常量 字符 ‘s‘ 转义字符 \n \101(8进制)\x42(16进制) 字符串常量 "aa" 符号常量 #define PI 3.1415926 程序编译后替换所有PI
- 变量
先声明后使用 int a = 11; 常变量,不允许修改值 const int a = 111;
- 常量
- 标识符
只能由数字,字母,下划线组成,开头必须是字母或者下划线
- 数据类型
- 基本类型
整型类型 基本整型 int Turbo C2.0中占用2个字节,Visual C++中占用4个字节 短整型 short int Turbo C2.0中占用2个字节,Visual C++中占用2个字节 长整型 long int long a = 111L; Turbo C2.0中占用4个字节,Visual C++中占用4个字节 双长整型 long long int Turbo C2.0中占用8个字节,Visual C++中占用8个字节 说明:以上几种数据类型,可以添加unsigned表示正值,如 unsigned int. 默认值signed,无符号类型的存储范围可以扩大一倍 注意,小数(实型)不能使用unsigned修饰 unsigned int a = 3;printf("%u\n", a); 字符型 char,占用一个字节,也可以添加unsigned修饰 char a = ‘a‘; printf("%c\n", a); 布尔型 bool,1代表真,0代表假 使用sizeof可以得出类型的占用字节数 sizeof (int) 浮点类型(实型) 单精度浮点型 float,占用4个字节 双精度浮点型 double,占用8个字节 double a = 1; printf("%.2lf\n", a); // 保留2位小数 长双精度浮点型 long double Turbo C2.0中占用16个字节,Visual C++中占用8个字节 基本数据类型可以进行强制类型转换,如 double a = 1; float b = (float)a;
- 枚举类型 enum
enum test { first = 1, second, third }; enum test a = second; printf("%d\n", a); // 2
- 空类型 void
- 派生类型
指针类型 数组类型 [] 一维数组 int arr[10]; 声明 arr[0] = 10; 赋值 int arr[2] = { 10,11 }; 初始化 int arr[] = { 10,11 }; 二维数组 int arr[2][3]; 声明 arr[0][0] = 1; 赋值 int arr[2][3] = { {1, 2, 3}, {4, 5, 6} }; 初始化 或 int arr[2][3] = { 1, 2, 3, 4, 5, 6 }; 或 int arr[][3] = { 1, 2, 3, 4, 5, 6 }; 字符数组 字符串的存储形式就是字符数组,结束标志是 ‘\0‘ char arr[] = "so easy"; 声明 或 char arr[] = { "so easy" }; 系统自动在数组末尾添加 ‘\0‘ printf("%s\n", arr); 输入输出不需要地址符& char arr[5]; scanf("%s", arr); printf("%s\n", arr); 字符数组函数使用,需要 #include<string.h> puts输出字符数组 char arr[] = "so ea\0sy"; puts(arr); gets输入字符数组 char arr[5]; gets_s(arr); // 注意输入aaaa,系统默认末尾添加\0表示5个字符 strcat字符数组拼接,将结果放到第一个参数中 char arr[12] = "nihao"; char arr1[6] = "buhao"; strcat(arr, arr1); puts(arr); strcpy给字符数组赋值 char arr[5]; strcpy(arr, "aa"); 或者 char arr[5], arr1[5] = "bb"; strcpy(arr, arr1); strncpy给字符数组赋值制定个数字符 char arr[5], arr1[5] = "b\0b"; strncpy(arr, arr1, 2); strcmp用来比较两个字符串的大小 char arr[5] = "111", arr1[5] = "222"; int result = strcmp(arr, arr1); 英文字母小写比大写大,排在后面的比前面大 arr大于arr1的,函数返回正整数,小的返回负整数,相等返回0 strlen返回字符串实际长度 char arr[5] = "111"; int result = strlen(arr); strlwr转小写 char arr[5] = "AAA"; strlwr(arr); printf("%s\n", arr); strupr转大写 结构体类型 struct 共用体类型 union 函数类型 函数声明和调用 int main() { void fn1(); void fn2(char arr[]); fn1(); char arr[] = "c language is so easy\n"; fn2(arr); fn1(); return 0; } void fn1() { printf("*********************\n"); } void fn2(char arr[]) { // 不需要指定数组大小,只用来接受首元素地址 printf("%s\n", arr); }
- 基本类型
- 运算符
- 算术运算符
+ - * / 实数相除得双精度浮点,整数相除得整数部分,负数相除向零靠拢 % ++ --
- 关系运算符
< <= > >= == != 优先级,从上到下依次降低 ! 算术运算符 < <= > >= == != && || =
- 逻辑运算符
逻辑与 a != b && 1 != 2 逻辑或 a != b || 1 == 2 逻辑非 !a
- 算术运算符
- 输入输出语句
printf函数
常用的格式字符 d或者i 有符号十进制整数,long使用ld表示,long long使用lld表示 int a = 11111; printf("%8d\n", a); // 制定输出占8列 printf("%5d\n", a); c 用来输出字符 char a = ‘a‘; printf("%c\n", a); s 用来输出字符串 printf("%s\n", "aa"); f 用来输出实型数据 默认小数位数6位 double a = 1; printf("%f\n", a); 1.000000 指定小数位数 double a = 1111; printf("%0.10f\n", a); e 用来输出指数 double a = 1111; printf("%e\n", a); 1.111000e+03 printf("%0.2e\n", a); 1.11e+03 o 用来输出8进制整数 x 用来表示16进制整数 u 用来表示无符号10进制整数 g 用来输出浮点数,自动选择f或者e,谁输出的长度短,就选谁
scanf函数
一般使用scanf_s scanf_s("%d,%d", &a, &b); // 输入 1,2 这种格式获取数据 scanf_s("%d%d", &a, &b); // 输入 1 2 这种格式获取数据
putchar
输出字符 putchar(‘a‘);
getchar
输入字符 char a, b; a = getchar(); b = getchar(); // 输入gd,然后按enter键
- 流程控制语句
if...else... a>b?a:b switch结构 char a = ‘c‘; switch (a) { case ‘a‘: printf("a"); break; case ‘b‘: printf("b"); break; default: printf("no"); break; } while(...){...} do{...}while(...) for (int i = 0; i < 100; i++) { } break 立即跳出循环 continue 终止本次循环
- 变量和函数的属性
变量和函数都有两个属性,数据类型和数据存储类别 局部变量的存储类别 auto变量 函数调用完毕自动释放变量的存储空间,局部变量默认都是auto变量,auto关键字可以省略 将变量存储在动态存储区 auto a = 1; static变量 函数调用完毕后不销毁,保留原始值 static int a = 1; 将变量存储在静态存储区 register变量 某一变量读写频繁,可以定义成register将值存在cpu的寄存器中 目前系统可以自动完成这一功能 全局变量的存储类别 extern扩展全局变量作用域 void fn1() { extern int a; // 将变量的作用域扩展到此处 printf("%d\n", a); } int a = 1; 在其他c文件中,同样可以使用extern关键字,直接调用其他文件定义的全局变量 如果想限制其他文件访问此文件的全局变量,可以直接 static int a = 1; 这里的static关键字,仅仅用来限定作用域,不会改变存储区 函数的存储类别 默认是extern,此关键字可以省略不写 将作用域限定在当前文件,加static限定即可
- 指针
- 创建指针变量
int a = 1; int *b = &a; // 创建指针变量,&a用来表示整型数据的地址 printf("%d\n", *b); // 通过*b访问指针变量b对应的变量
- 指针变量简单的应用
输入两个数,由小到大排序 int main() { void fn(int *c, int *d); int a, b; scanf("%d%d", &a, &b); int *c = &a, *d = &b; fn(c, d); printf("%d,%d\n", a, b); return 0; } void fn(int *c, int *d) { int tmp; if (*c > *d) { tmp = *d; *d = *c; *c = tmp; } }
- 指针变量在数组中的应用
int arr[] = { 1,2,3,4,5 }; int *p1 = arr, *p2 = &arr[0]; printf("%o\n", p1); // 105374130 printf("%o\n", p2); // 105374130 数组名代表数组首元素的地址,即 arr == &arr[0] 指针变量的加减运算 当指针指向数组元素时,指针变量的加减运算才有意义 地址加整数 int arr[] = { 1,2,3,4,5 }; int *p1 = &arr[0]; int *p2 = p1 + 1; // 访问数组的下个元素,+1 相当于加一个数组元素所占用的字节数 printf("%d\n", *p2); // 2 指针变量十进制值 p1 -> 5241000 p2 -> 5241004 地址减地址 p2 - p1; // 1 表示p2对应的元素和p1对应的元素相隔的距离 地址加地址,无意义 利用指针快速遍历数组 int arr[] = { 1,2,3,4,5 }, *p; for (p = arr; p < arr + 5; p++) { printf("%d", *p); } c语言中访问数组的[]其实是一个语法糖,arr[i] 等价于 *(arr + i),也就是说,p[i] 等价于 *(p + i) 使用技巧 *p++ *++p 先进行++运算,然后进行*计算 在二维数组中使用指针 int arr[][2] = { {1,2}, {3,4} }; printf("%d\n", *(arr + 1)); // 9174020 printf("%d\n", *(arr[0] + 1)); // 2 arr表示二维数组第一行的地址等价于arr[0],arr[0]表示第一行第一列的地址等价于arr[0][0] 注意,arr 和 arr[0] 内存地址是一样的,但是数据类型不一样 int (*p2)[2] = arr; 代表一维数组,表示二维数组中行的指针
- 指针变量在字符串中的使用
字符串其实就是字符数组 char arr[] = "c language is so easy"; printf("%c\n", *arr); // c 数组名代表字符串第一个字符的地址 使用指针表示字符串 char *arr = "c language is so easy"; // 最好加上const printf("%s\n", arr); 提示:如果你的编辑器出现了错误提示,请在c++编译器命令行附加选项中添加 /Zc:strictStrings- 复制字符串 char *str = "c language is so easy", str1[50]; int i; for ( i = 0; *(str + i) != ‘\0‘; i++) { *(str1 + i) = *(str + i); } *(str1 + i) = ‘\0‘; printf("%s\n%s\n", str, str1);
- 指针变量在函数中的使用
基本使用 int main() { int fn(int); int (*p)(int) = fn; // 声明函数指针变量并赋值 printf("%d\n", (*p)(1)); // (*p)(1) 和 p(1) 效果一样 return 0; } int fn(int a) { return ++a; } 函数作为另一个函数的参数 int main() { void fn1(int (*fun)(int)); int fn(int); fn1(fn); return 0; } int fn(int a) { return ++a; } void fn1(int (*fun)(int)) { printf("%d\n", fun(2)); } 函数的返回值是指针 int main() { char * fn(); char *p = fn(); printf("%s\n", p); return 0; } char * fn() { char *str = "c language is so easy"; return str; }
- 指针的其他应用
指针数组 数组中的每一个元素可以是指针 char * arr[] = { "a", "b", "c" }; 指向指针数据的指针变量 char * arr[] = { "a", "b", "c" }, **p; for (int i = 0; i < 3; i++) { p = arr + i; printf("%s\n", *p); } main函数的参数 int main(int length, char * params[]) { for (int i = 0; i < length; i++) { printf("%s%c", *(params + i), (i == (length- 1)?‘\n‘:‘ ‘)); } return 0; } 通过命令行输入 .\ConsoleApplication1.exe 1 2 3 a b c length得到的值是7,params就是参数的指针数组 动态内存分配 c语言的非静态局部变量存储在动态存储区,这个存储区称为栈 c语言允许用户自定义内存动态存储区,这个存储区称为堆,通过指针来引用,c提供下面的库函数来实现这一功能 需要导入#include<stdlib.h> malloc函数 用来开辟动态存储区 malloc(100); // 创建100个字节的空间,返回的指针为void类型 calloc函数 用来创建50个4个字节长度的连续空间 calloc(50, 4); // 返回的指针为void类型 realloc函数 用来将开辟的动态存储区重新划分 void *p = calloc(50, 4); realloc(p, 50); // 将p指向的存储区重新规划成50个字节大小的存储区,返回的指针为void类型 free函数 释放已经开辟的动态存储区 void *p = calloc(50, 4); free(p); // 无返回值 注意 void类型的指针不能存储数据,使用之前必须重新分派类型,应当如下使用 int* p = (int*)malloc(100); // 简写, 使用demo int* p = (int *)malloc(5 * sizeof(int)); for (int i = 0; i < 5; i++) { scanf("%d", p + i); } for (int i = 0; i < 5; i++) { if (*(p + i) < 10) { printf("%d\n", *(p + i)); } }
- 创建指针变量
- 结构体
结构体的作用是声明自定义数据类型 基本使用 struct Student { char name[10]; int age; char sex[4]; } student1, student2; // 定义类型并声明变量 struct Class { char ClassName[10]; struct Student s; // 可以实现嵌套struct }; struct Class class1 = { "初一10班", {"叶家伟", 10, "女"} }; // 声明变量,struct Class表示类型 printf("%s|%s|%d|%s\n", class1.ClassName, class1.s.name, class1.s.age, class1.s.sex); 结构体数组 struct stu { int a; }; struct stu arr[3] = { {1},{2},{3} }; for (int i = 0; i < 3; i++) { printf("%d\n", arr[i].a); } 结构体指针的使用 struct stu { int a; }; struct stu demo = { 1 }; struct stu* p = &demo; printf("%d\n", demo.a); // 1 printf("%d\n", (*p).a); // 1 printf("%d\n", p->a); // 1 结构体指针数组的使用 struct stu arr[3] = { {1}, {2}, {3} }, *p; for (p = arr; p < arr + 3; p++) { printf("%d\n", (*p).a); }
- 结构体在数据结构中的使用
- 链表
静态链表 struct stu { int a; struct stu* next; }; struct stu stu1, stu2, stu3, *head; stu1.a = 1; stu2.a = 2; stu3.a = 3; head = &stu1; stu1.next = &stu2; stu2.next = &stu3; stu3.next = NULL; do { printf("%d\n", head->a); head = head->next; } while (head != NULL); 动态链表 使用前面讲的动态内存分配区函数可以创建动态链表 struct stu { int a; struct stu* next; }; struct stu * fn() { struct stu *p1= (struct stu*)malloc(sizeof(struct stu)), *head = p1; scanf("%d", &(p1->a)); for (int i = 0; i < 2; i++) { struct stu *p2 = (struct stu*)malloc(sizeof(struct stu)); scanf("%d", &(p2->a)); if (i == 1) { p1->next = p2; p2->next = NULL; } else { p1->next = p2; p1 = p2; } } return head; } int main(int length, char * params[]) { struct stu * fn(), *p; p = fn(); do { printf("%d\n", p->a); p = p->next; } while (p != NULL); return 0; }
- 链表
- 共用体类型
共用体类型和结构体类似,不过共用体中的成员共用内存空间,以最长的数据类型所占的空间为主 union test { int i; float j; char c; }; union test a; a.i = 99; printf("%d\n", a.i); // 99 printf("%f\n", a.j); // 0.000000 printf("%c\n", a.c); // c 共用体类型只能对一个成员赋值
- typedef关键字的使用
typedef关键字用来给已知的数据类型取别名,用法如下 基本数据类型名替换 typedef int Integer; Integer i = 111; printf("%d\n", i); 结构体取别名 typedef struct { int i; } test; test i = { 1 }; printf("%d\n", i.i); 数组取别名 typedef int arr[5]; arr test = { 1,2,3,4,5 }; printf("%d\n", test[0]); 指针取别名 int arr[5] = { 1,2,3,4,5 }; typedef int* p; p test = arr; printf("%d\n", *test); 函数指针取别名 int main() { void fn(); typedef void(*test)(); test f = fn; f(); return 0; } void fn() { printf("%s\n", "调用了"); }
- 文件操作
文件名 ?F:\Test\Test.java ?F:\Test 文件路径 Test 文件名主干 java 文件名后缀 文件的分类 ASCLL文件,也叫映像文件,占用内存多,转换耗时 二进制文件,也叫文本文件,就是原始文件 文件缓冲区 每一个正在使用的文件都会自动开辟一个文件缓冲区,用来存放临时数据 指向文件的指针变量 FILE* f; 打开文件 FILE* f = fopen("F:\\demo.txt", "r"); // 这个路径不能复制过来,只能手动输入 if (f == NULL) { perror("Error"); exit(0); // 此函数是终止程序,需要 #include<stdlib.h> } printf("%d\n", fclose(f)); 文本文件 r 只读,文件不存在出错 w 只写,创建新文件 a 追加,文件不存在出错 r+ 读写,文件不存在出错 w+ 读写,创建新文件 a+ 读写,文件不存在出错 二进制文件 rb 只读,文件不存在出错 wb 只写,创建新文件 ab 追加,文件不存在出错 rb+ ... wb+ ... ab+ ... 提示:带b的和不带b的区别,不带b的会把\n转化成\r和\n 标准流文件 标准输入流,标准输出流,标准出错输出流,系统已经定义了这3个文件的指针变量 stdin, stdout, stderr 关闭文件 调用fclose函数可以将文件缓冲区中的数据输出到磁盘中,然后再撤销文件信息区 fclose(f); 读写字符 写字符fputc,简写 putc FILE* f = fopen("F:\\demo.txt", "w"); if (f == NULL) { perror("Error"); exit(0); } printf("%d\n", fputc(‘a‘, f)); // 写字符,成功则返回字符,不成功返回-1,即EOF printf("%d\n", fclose(f)); // 关闭文件流成功返回0,不成功返回-1,即EOF 读字符fgetc,简写 getc FILE* f = fopen("F:\\demo.txt", "r"); if (f == NULL) { perror("Error"); exit(0); } printf("%d\n", fgetc(f)); // 读字符,成功则返回字符,不成功返回-1,即EOF printf("%d\n", fclose(f)); 复制文件 FILE* in = fopen("F:\\demo.txt", "r"); FILE* out = fopen("F:\\demo1.txt", "w"); if (in == NULL || out == NULL) { perror("Error"); exit(0); } char ch = fgetc(in); // 读取输入流第一个字符 while (!feof(in)) { // 判断输入流是否已到末尾,等价于 while (ch != EOF) fputc(ch, out); ch = fgetc(in); // 读取下一个字符 } fclose(in); fclose(out); 读写字符串 写字符串fputs FILE* f = fopen("F:\\demo.txt", "w"); if (f == NULL) { perror("Error"); exit(0); } fputs("c language is so easy", f); // 执行成功,返回0,不成功,返回EOF fclose(f); 读取字符串fgets FILE* f = fopen("F:\\demo.txt", "r"); if (f == NULL) { perror("Error"); exit(0); } char str[50]; fgets(str, 23, f); // 读取22个字符,并且存到str中,如果遇到换行符\n或者EOF,就结束读取,其中\n是会读到结果中的,执行成功返回地址,不成功返回NULL fclose(f); printf(str); 格式化读写字符串 格式化写 FILE* f = fopen("F:\\demo.txt", "w"); if (f == NULL) { perror("Error"); exit(0); } float i = 1; int j = 2; fprintf(f, "%.2f, %d", i, j); fclose(f); 格式化读 FILE* f = fopen("F:\\demo.txt", "r"); if (f == NULL) { perror("Error"); exit(0); } float i; int j; fscanf(f, "%f, %d", &i, &j); fclose(f); printf("%f, %d\n", i, j); 二进制方式读写数据 写数据fwrite struct test { int i; } t = { 1 }; FILE* f = fopen("F:\\demo.dat", "wb"); if (f == NULL || fwrite(&t, sizeof(struct test), 1, f) != 1) { // fwrite函数返回值是读取数据的个数 perror("Error"); exit(0); } fclose(f); 读数据fread struct test { int i; } t; FILE* f = fopen("F:\\demo.dat", "rb"); if (f == NULL || fread(&t, sizeof(struct test), 1, f) != 1) { // fread函数返回值是写数据的个数 perror("Error"); exit(0); } printf("%d\n", t.i); 控制文件位置标记 将位置移动到开头 FILE* f = fopen("F:\\demo.txt", "w+"); if (f == NULL) { perror("Error"); exit(0); } fputs("c language is so easy", f); char str[50]; rewind(f); // 将文件位置指针挪到开头 fgets(str, 23, f); // c language is so easy printf(str); fclose(f); 随意移动指针 一上面demo为例 SEEK_CUR fseek(f, -5L, SEEK_CUR); 以当前位置为准将位置向前移动5个字节 fgets(str, 23, f); // " easy" SEEK_SET fseek(f, 5L, SEEK_SET); 以开始位置为准将位置向后移动5个字节 fgets(str, 23, f); // ‘guage is so easy‘ SEEK_END 表示结尾 获取文件当前指针位置 int i = ftell(f); // 相对于文件起始位置 if (i == -1L) { // 获取不到返回-1L printf("error\n"); } else { printf("%ld\n", i); } 检查错误 ferror函数 当调用各种输入输出函数时,如果出现错误ferror返回非0值 printf("%d\n", ferror(f)); clearerr函数 当文件读写出错,要调用 clearerr(f); 清空文件读写错误标志
原文地址:https://www.cnblogs.com/ye-hcj/p/8511339.html
时间: 2024-11-20 18:08:17