指针和函数:
栈 帧:
当函数调用时,系统会在 stack 空间上申请一块内存区域,用来供函数调用,主要存放 形参 和 局部变量(定义在函数内部)。
当函数调用结束,这块内存区域自动被释放(消失)。
传值和传址:
传值:函数调用期间,实参将自己的值,拷贝一份给形参。
传址:函数调用期间,实参将地址值,拷贝一份给形参。 【重点】
(地址值 --》 在swap函数栈帧内部,修改了main函数栈帧内部的局部变量值)
指针做函数参数:
int swap2(int *a, int *b);
int swap2(char *a, char *b);
调用时,传有效的地址值。
数组做函数参数:
void BubbleSort(int arr[10]) == void BubbleSort(int arr[]) == void BubbleSort(int *arr)
传递不再是整个数组,而是数组的首地址(一个指针)。
所以,当整型数组做函数参数时,我们通常在函数定义中,封装2个参数。一个表数组首地址,一个表元素个数。
指针做函数返回值:
int *test_func(int a, int b);
指针做函数返回值,不能返回【局部变量的地址值】。
数组做函数返回值:
C语言,不允许!!!! 只能写成指针形式。
指针和字符串:
1)
char str1[] = {'h', 'i', '\0'}; 变量,可读可写
char str2[] = "hi"; 变量,可读可写
char *str3 = "hi"; 常量,只读
str3变量中,存储的是字符串常量“hi”中首个字符‘h’的地址值。
str3[1] = 'H'; // 错误!!
char *str4 = {'h', 'i', '\0'}; // 错误!!!
2)
当字符串(字符数组), 做函数参数时, 不需要提供2个参数。 因为每个字符串都有 '\0'。
练习:比较两个字符串: strcmp();实现
比较 str1 和 str2, 如果相同返回0, 不同则依次比较ASCII码,str1 > str2 返回1,否则返回-1
数组方式:
int mystrcmp(char *str1, char *str2)
{
int i = 0;
while (str1[i] == str2[i]) // *(str1+i) == *(str2+i)
{
if (str1[i] == '\0')
{
return 0; // 2字符串一样。
}
i++;
}
return str1[i] > str2[i] ? 1 : -1;
}
指针方式:
int mystrcmp2(char *str1, char *str2)
{
while (*str1 == *str2) // *(str1+i) == *(str2+i)
{
if (*str1 == '\0')
{
return 0; // 2字符串一样。
}
str1++;
str2++;
}
return *str1 > *str2 ? 1 : -1;
}
练习:字符串拷贝:
//数组版本
void mystrcpy(char *src, char *dst)
{
int i = 0;
while (src[i] != 0) // src[i] == *(src+i)
{
dst[i] = src[i];
i++;
}
dst[i] = '\0';
}
//指针版
void mystrcpy2(char *src, char *dst)
{
while (*src != '\0') // src[i] == *(src+i)
{
*dst = *src;
src++;
dst++;
}
*dst = '\0';
}
练习:在字符串中查找字符出现的位置:
char *myStrch(char *str, char ch)
{
while (*str)
{
if (*str == ch)
{
return str;
}
str++;
}
return NULL;
}
// hellowrld --- 'o'
char *myStrch2(char *str, char ch)
{
int i = 0;
while (str[i])
{
if (str[i] == ch)
{
return &str[i];
}
i++;
}
return NULL;
}
练 习:字符串去空格。
void str_no_space(char *src, char *dst)
{
int i = 0; // 遍历字符串src
int j = 0; // 记录dst存储位置
while (src[i] != 0)
{
if (src[i] != ' ')
{
dst[j] = src[i];
j++;
}
i++;
}
dst[j] = '\0';
}
// 指针版
void str_no_space2(char *src, char *dst)
{
while (*src != 0)
{
if (*src != ' ')
{
*dst = *src;
dst++;
}
src++;
}
*dst = '\0';
}
带参数的main函数:
无参main函数: int main(void) == int main()
带参数的main函数: int main(int argc, char *argv[]) == int main(int argc, char **argv)
参1:表示给main函数传递的参数的总个数。
参2:是一个数组!数组的每一个元素都是字符串 char *
测试1:
命令行中的中,使用gcc编译生成 可执行文件,如: test.exe
test.exe abc xyz zhangsan nichousha
-->
argc --- 5
test.exe -- argv[0]
abc -- argv[1]
xyz -- argv[2]
zhangsan -- argv[3]
nichousha -- argv[4]
测试2:
在VS中。项目名称上 --》右键--》属性--》调试--》命令行参数 --》将 test.exe abc xyz zhangsan nichousha 写入。
-->
argc --- 5
test.exe -- argv[0]
abc -- argv[1]
xyz -- argv[2]
zhangsan -- argv[3]
nichousha -- argv[4]
str 中 substr 出现次数:
strstr函数: 在 str中,找substr出现的位置。
char *strstr(char *str, char *substr) -- #include <string.h>
参1: 原串
参2: 子串
返回值: 子串在原串中的位置。(地址值);
如果没有: NULL
实 现:
int str_times(char *str, char *substr)
{
int count = 0;
char *p = strstr(str, substr); // "llollollo"
while (p != NULL)
{
count++;
p += strlen(substr); // p = p+strlen(substr) --> "llollo"
p = strstr(p, substr); // 返回: "llo"
}
return count;
}
求非空字符串元素个数:
字符串逆置: str_inverse
判断字符串是回文:
字符串处理函数:
字符串拷贝:
字符串拼接:
字符串比较:
字符串格式化输入、输出:
sprintf():
sscanf():
字符串查找字符、子串:
strchr()
strrchr()
strstr()
字符串分割:
strtok()
atoi/atof/atol:
01-传值和传址.c
int swap(int, int); // 函数声明
int swap2(int *, int *);
int main0101(void)
{
int m = 23;
int n = 57;
printf("--before-- m = %d, n = %d\n", m, n);
// 函数调用
//swap(m, n); // m/n 实参
swap2(&m, &n);
printf("--after-- m = %d, n = %d\n", m, n);
system("pause");
return EXIT_SUCCESS;
}
int swap2(int *a, int *b) // 形参a、b, 需传地址值
{
int tmp = 0;
tmp = *a;
*a = *b;
*b = tmp;
return 0;
}
// 函数定义
int swap(int a, int b) // a/b 形参
{
int tmp = 0;
tmp = a;
a = b;
b = tmp;
return 0;
}
02-数组做函数参数.c
//void BubbleSort(int arr[]) // void BubbleSort(int *arr)
void BubbleSort(int *arr, int n)
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
int main0202(void)
{
int arr[] = {5, 89, 3, 22, 40, 31, 9, 22, 67, 28, 45, 78};
printf("main: sizeof(arr) = %d\n", sizeof(arr));
int n = sizeof(arr) / sizeof(arr[0]);
BubbleSort(arr, n);
for (size_t i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
system("pause");
return EXIT_SUCCESS;
}
03-数组做函数参数测试.c
void test_func(int arr[])
{
printf("size 2 = %u\n", sizeof(arr)); // 整个数组大小
printf("%d\n", arr[0]);
}
int main0301(void)
{
int arr[] = { 4, 5, 5, 6, 7 };
printf("size 1 = %u\n", sizeof(arr)); // 整个数组大小
test_func(arr);
system("pause");
return EXIT_SUCCESS;
}
04-指针做函数返回值.c
int m = 100; // 全局变量 对应空间消失 ==> 程序结束。
int *test_func2(int a, int b)
{
int p = 1234; // 局部变量
//return &m;
return &p;
}
int main0401(void)
{
int *ret = NULL; // NULL == 0
ret = test_func2(10, 20);
printf("ret = %d\n", *ret);
system("pause");
return EXIT_SUCCESS;
}
05-指针和字符串.c
int main(void)
{
char str1[] = "hello"; // {'h',, 'e', 'l', 'l', 'o', '\0'}
char m[] = "hello";
char *str2 = "hello"; // "hello" 是一个字符串常量, 不能修改。
char *n = "hello";
str1[0] = 'R';
str2[0] = 'R';
printf("str1 = %p\n", str1);
printf("m = %p\n", m);
printf("str2 = %p\n", str2);
printf("n = %p\n", n);
system("pause");
return EXIT_SUCCESS;
}
06-字符串比较.c
// str1 和 str2 == -->0 str1 > str2 --> 1, str1
int mystrcmp(char *str1, char *str2)
{
int i = 0;
while (str1[i] == str2[i]) // *(str1+i) == *(str2+i)
{
if (str1[i] == '\0')
{
return 0; // 2字符串一样。
}
i++;
}
return str1[i] > str2[i] ? 1 : -1;
}
int mystrcmp2(char *str1, char *str2)
{
while (*str1 == *str2) // *(str1+i) == *(str2+i)
{
if (*str1 == '\0')
{
return 0; // 2字符串一样。
}
str1++;
str2++;
}
return *str1 > *str2 ? 1 : -1;
}
int main0601(void)
{
char *str1 = "helloz";
char *str2 = "helloz";
//int ret = mystrcmp(str1, str2);
int ret = mystrcmp2(str1, str2);
if (ret == 0)
printf("相同\n");
else if (ret == 1)
printf("str1 > str2\n");
else if (ret == -1)
printf("str1 < str2\n");
else
printf("异常\n");
system("pause");
return EXIT_SUCCESS;
}
07-字符串拷贝.c
// src: 源 dst: 目标
//数组版本
void mystrcpy(char *src, char *dst)
{
int i = 0;
while (src[i] != 0) // src[i] == *(src+i)
{
dst[i] = src[i];
i++;
}
dst[i] = '\0';
}
//指针版
void mystrcpy2(char *src, char dst)
{
while (src != '\0') // src[i] == *(src+i)
{
*dst = *src;
src++;
dst++;
}
*dst = '\0';
}
int main0701(void)
{
char *src = "helloworldfuoie11ll";
char dst[100];
mystrcpy2(src, dst);
printf("dst = %s\n", dst);
system("pause");
return EXIT_SUCCESS;
}
08-在字符串中找字符.c
// hellowrld --- 'm'
char *myStrch(char *str, char ch)
{
while (str)
{
if (str == ch)
{
return str;
}
str++;
}
return NULL;
}
// hellowrld --- 'o'
char *myStrch2(char *str, char ch)
{
int i = 0;
while (str[i])
{
if (str[i] == ch)
{
return &str[i];
}
i++;
}
return NULL;
}
int main0801(void)
{
char str[] = "hello world";
char ch = ' ';
char *ret = NULL;
ret = myStrch2(str, ch);
printf("ret = %s\n", ret);
system("pause");
return EXIT_SUCCESS;
}
09-字符串去空格.c
// src : 有空格字符串, dst:没有空格的字符串
void str_no_space(char *src, char *dst)
{
int i = 0; // 遍历字符串src
int j = 0; // 记录dst存储位置
while (src[i] != 0)
{
if (src[i] != ' ')
{
dst[j] = src[i];
j++;
}
i++;
}
dst[j] = '\0';
}
// 指针版
void str_no_space2(char *src, char *dst)
{
while (src != 0)
{
if (src != ' ')
{
*dst = *src;
dst++;
}
src++;
}
*dst = '\0';
}
int main0901(void)
{
char str[] = "ni chou sha chou ni za di";
char dst[100] = {0};
str_no_space2(str, dst);
printf("dst = %s\n", dst);
system("pause");
return EXIT_SUCCESS;
}
10-带参数的main.c
int main1001(int argc, char *argv[])
{
int i;
for (i = 0; i < argc; i++)
{
printf("argv[%d] = %s\n", i, argv[i]);
}
system("pause");
return EXIT_SUCCESS;
}
11-字符串中找子串.c
//strstr函数测试
int main1101(void)
{
char *ret = strstr("hellollollo", "llo");
printf("ret = %s\n", ret);
system("pause");
return EXIT_SUCCESS;
}
int str_times(char *str, char *substr)
{
int count = 0;
char *p = strstr(str, substr); // "llollollo"
while (p != NULL)
{
count++;
p += strlen(substr); // p = p+strlen(substr) --> "llollo"
p = strstr(p, substr); // 返回: "llo"
}
return count;
}
// 统计字符串中,子串出现的次数。
int main1102(void)
{
char str[] = "helloabclloxyzllo";
char substr[] = "llo";
int ret = str_times(str, substr);
printf("出现%d次\n", ret);
system("pause");
return EXIT_SUCCESS;
}
求非空字符串元素个数:
“ni chou sha chou ni za di”
字符串逆置: str_inverse
hello -- olleh
void str_inserse(char *str)
{
char *start = str; // 记录首元素地址
char *end = str + strlen(str) - 1; // 记录最后一个元素地址。
while (start < end) // 首元素地址是否 < 最后一个元素地址
{
char tmp = *start; // 三杯水 char 元素交换
*start = *end;
*end = tmp;
start++; // 首元素对应指针后移
end--; // 尾元素对应指针前移
}
}
判断字符串是回文:
int str_abcbb(char *str)
{
char *start = str; // 记录首元素地址
char *end = str + strlen(str) - 1; // 记录最后一个元素地址。
while (start < end) // 首元素地址是否 < 最后一个元素地址
{
if (*start != *end) // 判断字符是否一致。
{
return 0; // 0 表示非 回文
}
start++;
end--;
}
return 1; // 1 表示 回文
}
字符串处理函数: #include <string.h>
字符串拷贝:
strcpy:
将 src 的内容,拷贝给 dest。 返回 dest。 保证dest空间足够大。【不安全】
char *strcpy(char *dest, const char *src);
函数调用结束 返回值和 dest参数结果一致。
strncpy:
将 src 的内容,拷贝给 dest。只拷贝 n 个字节。 通常 n 与dest对应的空间一致。
默认 不添加 ‘\0’
char *strncpy(char *dest, const char *src, size_t n);
特性: n > src: 只拷贝 src 的大小
n < src: 只拷贝 n 字节大小。 不添加 ‘\0’
字符串拼接:
strcat:
将 src 的内容,拼接到 dest 后。 返回拼接后的字符串。 保证 dest 空间足够大。
char *strcat(char *dest, const char *src);
strncat:
将 src 的前 n 个字符,拼接到 dest 后。 形成一个新的字符串。保证 dest 空间足够大。
char *strncat(char *dest, const char *src, size_t n);
函数调用结束 返回值和 dest 参数结果一致。
字符串比较: 不能使用 > < >= <= == !=
strcmp:
比较s1和s2两个字符串,如果相等 返回0.如果不相等,进一步表 s1 和 s2 对应位 ASCII码值。
s1 > s2 返回1
s1 < s2 返回-1
int strcmp(const char *s1, const char *s2);
strncmp:
int strncmp(const char *s1, const char *s2, size_t n);
比较s1和s2两个字符串的前n个字符,
如果相等 返回0。如果不相等,进一步表 s1 和 s2 对应位 ASCII码值。(不比字符串ASCII码的和)
s1 > s2 返回1
s1 < s2 返回-1
字符串格式化输入、输出:
sprintf(): s -- string
int sprintf(char *str, const char *format, ...);
对应printf,将原来写到屏幕的“格式化字符串”,写到 参数1 str中。
printf("%d+%d=%d\n", 10, 24, 10+24);
---》
char str[100];
sprintf(str, "%d+%d=%d\n", 10, 24, 10+24); 格式串写入str数组中。
sscanf():
int sscanf(const char *str, const char *format, ...);
对应scanf, 将原来从屏幕获取的“格式化字符串”, 从 参数1 str中 获取。
scanf("%d+%d=%d", &a, &b, &c);
---》
char str[]= "10+24=45";
sscanf(str, "%d+%d=%d", &a, &b, &c); a --> 10, b --> 24, c --> 45
字符串查找字符、子串:
strchr():
在字符串str中 找一个字符出现的位置。 返回字符在字符串中的地址。
char *strchr(const char *s, int c);
printf("%s\n" strchr("hehehahahoho", 'a')); --> "ahahoho"
strrchr():
自右向左,在字符串str中 找一个字符出现的位置。 返回字符在字符串中的地址。
char *strrchr(const char *s, int c);
printf("%s\n" strrchr("hehehahahoho", 'a')); --> "ahoho"
strstr():
在字符串str中,找子串substr第一次出现的位置。返回地址。
char *strstr(const char *str, const char *substr);
在字符串中找子串的位置。
printf("%s\n" strrchr("hehehahahoho", "ho")); --> "hoho"
printf("%s\n" strrchr("hehehahahoho", "xixi")); --> NULL
scanf("%s", str);
scanf("%[^\n]", str);
字符串分割:
strtok(): 按照既定的分割符,来拆分字符串。“www.baidu.com” --> "www\0baidu.com"
char *strtok(char *str, const char *delim);
参1: 待拆分字符串
参2: 分割符组成的“分割串”
返回:字符串拆分后的首地址。 “拆分”:将分割字符用 '\0'替换。
特性:
1)strtok拆分字符串是直接在 原串 上操作,所以要求参1必须,可读可写(char *str = "www.baidu.com" 不行!!!)
2)第一次拆分,参1 传待拆分的原串。 第1+ 次拆分时,参1传 NULL.
练习: 拆分 ".itcast.cn$This is a strtok$test"
char str[] = "www.itcast.cn$This is a strtok$test";
char *p = strtok(str, "$ .");
while (p != NULL)
{
p = strtok(NULL, " .$");
printf("p = %s\n", p);
}
atoi/atof/atol:
使用这类函数进行转换,要求,原串必须是可转换的字符串。
错误使用:"abc123" --> 0; "12abc345" ---> 12; "123xyz" -->123
atoi:字符串 转 整数。
int atoi(const char *nptr);
atof:字符串 转 浮点数
atol:字符串 转 长整数
----------------------------------------------------------------------------------------------
局部变量:
概念:定义在函数 内 部的变量。
作用域:从定义位置开始,到包裹该变量的第一个右大括号结束。
全局变量:
概念:定义在函数 外 部的变量。
作用域:从定义位置开始,默认到本文件内部。 其他文件如果想使用,可以通过声明方式将作用域导出。
static全局变量:
定义语法: 在全局变量定义之前添加 static 关键字。 static int a = 10;
作用域:被限制在本文件内部,不允许通过声明导出到其他文件。
static局部变量:
定义语法: 在局部变量定义之前添加 static 关键字。
特性: 静态局部变量只定义一次。在全局位置。 通常用来做计数器。
作用域:从定义位置开始,到包裹该变量的第一个右大括号结束。
全局函数: 函数
定义语法: 函数原型 + 函数体
static函数:
定义语法:static + 函数原型 + 函数体
static 函数 只能在 本文件内部使用。 其他文件即使声明也无效。
生命周期:
局部变量:从变量定义开始,函数调用完成。 --- 函数内部。
全局变量:程序启动开始,程序终止结束。 --- 程序执行期间。
static局部变量:程序启动开始,程序终止结束。 --- 程序执行期间。
static全局变量:程序启动开始,程序终止结束。 --- 程序执行期间。
全局函数:程序启动开始,程序终止结束。 --- 程序执行期间。
static函数:程序启动开始,程序终止结束。 --- 程序执行期间。
内存4区模型:
代码段:.text段。 程序源代码(二进制形式)。
数据段:只读数据段 .rodata段。初始化数据段 .data段。 未初始化数据段 .bss 段。
stack:栈。 在其之上开辟 栈帧。 windows 1M --- 10M Linux: 8M --- 16M
heap:堆。 给用户自定义数据提供空间。 约 1.3G+
开辟释放 heap 空间:
void *malloc(size_t size); 申请 size 大小的空间
返回实际申请到的内存空间首地址。 【我们通常拿来当数组用】
void free(void *ptr); 释放申请的空间
参数: malloc返回的地址值。
使用 heap 空间:
空间时连续。 当成数组使用。
free后的空间,不会立即失效。 通常将free后的 地址置为NULL。
free 地址必须 是 malloc申请地址。否则出错。
如果malloc之后的地址一定会变化,那么使用临时变量tmp 保存。
二级指针对应的 heap空间:
申请外层指针: char **p = (char **)malloc(sizeof(char *) * 5);
申请内层指针: for(i = 0; i < 5; i++)
{
p[i] = (char *)malloc(sizeof(char) *10);
}
使用: 不能修改 p 的值。
for(i = 0; i < 5; i++)
{
strcpy(p[i], "helloheap");
}
释放内层:
for(i = 0; i < 5; i++)
{
free(p[i]);
}
释放外层:
free(p);
栈的存储特性:
局部变量:
形参:
内存操作函数:
memset:
memmove:
memcmp:
内存常见问题:
1) 申请 0 字节空间
2)free空指针
3)越界访问
4)free ++后的地址
5)子函数malloc空间,main中用
01-非空字符串元素个数.c
int no_space_str(char *str)
{
int count = 0;
char *p = str;
while (*p)
{
if (*p != ' ')
{
count++;
}
p++;
}
return count;
}
int main0101(void)
{
char str[] = "ni chou sha";
int ret = no_space_str(str);
printf("%d\n", ret);
system("pause");
return EXIT_SUCCESS;
}
02-字符串逆序.c
// o e l l h
// 字符串逆序
void str_inserse(char *str)
{
//int i, j; // str[i] *(str+i)
char *start = str; // 记录首元素地址
char *end = str + strlen(str) - 1; // 记录最后一个元素地址。
while (start < end) // 首元素地址是否 < 最后一个元素地址
{
char tmp = *start; // 三杯水 char 元素交换
*start = *end;
*end = tmp;
start++; // 首元素对应指针后移
end--; // 尾元素对应指针前移
}
}
// 判断回文字符串 abcddpba
int str_abcbb(char *str)
{
char *start = str; // 记录首元素地址
char *end = str + strlen(str) - 1;// 记录最后一个元素地址。
while (start < end) // 首元素地址是否 < 最后一个元素地址
{
if (*start != *end) // 判断字符是否一致。
{
return 0; // 0 表示非 回文
}
start++;
end--;
}
return 1; // 1 表示 回文
}
int main0201(void)
{
char str[] = "this is a test";
str_inserse(str);
printf("str=%s\n ---------------------\n", str);
char s2[] = "abcmncba";
int ret = str_abcbb(s2);
if (ret == 0)
printf("不是回文\n");
else if (ret == 1)
printf("是回文\n");
system("pause");
return EXIT_SUCCESS;
}
03-字符串拷贝strcpy和strncpy.c
// strcpy
int main0301(void)
{
char src[] = "abc efg zhansan wangwu ";
char dest[10] = {0};
char *p = strcpy(dest, src); ;// 字符串src 拷贝给dest
printf("p= %s\n", p);
printf("dest = %s\n", dest);
system("pause");
return EXIT_SUCCESS;
}
// strncpy
int main0302(void)
{
char src[] = "hello world";
char dest[100] = { 0 };
char *p = strncpy(dest, src, 100); ;// 字符串src 拷贝给dest
for (size_t i = 0; i < 10; i++)
{
printf("%c\n", p[i]);
}
printf("p= %s\n", p);
printf("dest = %s\n", dest);
system("pause");
return EXIT_SUCCESS;
}
04-字符串拼接 strcat和strncat.c
int main0401(void)
{
char src[] = "world";
char dest[] = "hello";
char *p = strcat(dest, src);
printf("p = %s\n", p);
printf("dest = %s\n", dest);
system("pause");
return EXIT_SUCCESS;
}
int main0402(void)
{
char src[] = "world";
char dest[6] = "hello";
char *p = strncat(dest, src, 3);
printf("p = %s\n", p);
printf("dest = %s\n", dest);
printf("%d\n", strlen(dest));
system("pause");
return EXIT_SUCCESS;
}
05-strcmp和strncmp字符串比较.c
int main0501(void)
{
char *str1 = "helloworld";
char *str2 = "helloz";
printf("ret = %d\n", strcmp(str1, str2));
system("pause");
return EXIT_SUCCESS;
}
int main0502(void)
{
char *str1 = "helloworld";
char *str2 = "helloz";
printf("ret = %d\n", strncmp(str1, str2, 8));
system("pause");
return EXIT_SUCCESS;
}
06-格式化读入和写出 sprintf、sscanf.c
// sprintf
int main0601(void)
{
char buf[100] = {0}; //buffer string str source src
sprintf(buf, "%d%c%d=%d\n", 10, '+', 34, 10+34);
puts(buf);
system("pause");
return EXIT_SUCCESS;
}
// sscanf
int main0602(void)
{
char buf[100] = { 0 }; //buffer string str source src
int a, b, c;
char str[] = "13+56=89";
sscanf(str, "%d+%d=%d", &a, &b, &c);
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);
system("pause");
return EXIT_SUCCESS;
}
07-字符串分割strtok.c
int main0701(void)
{
char str[] = "www.itcast.cn.com.net"; // www itcast cn
char *p = strtok(str, "."); // 第一次拆分,参1 传 待拆分的原串。
while (p != NULL)
{
p = strtok(NULL, "."); // 第1+ 次拆分是,参1传 NULL.printf("%s\n", p);
}
system("pause");
return EXIT_SUCCESS;
}
int main0702(void)
{
char str[] = "www.itcast.cn$This is a strtok$test";
char *p = strtok(str, "$ .");
while (p != NULL)
{
p = strtok(NULL, ". $");
printf("p = %s\n", p);
}
system("pause");
return EXIT_SUCCESS;
}
08-atoi_atof_atol.c
static int a = 1034673;
void test1(void)
{
static int b = 0;
printf("b = %d\n", b++);
}
int main0801(void)
{
char str[] = "abc345";
int num = atoi(str);
printf("num = %d\n", num);
char str1[] = " -10";
int num1 = atoi(str1);
printf("num1 = %d\n", num1);
char str2[] = "0.123f";
double num2 = atof(str2);
printf("num2 = %.2lf\n", num2);
char str3[] = "123L";
long num3 = atol(str3);
printf("num3 = %ld\n", num3);
system("pause");
return EXIT_SUCCESS;
}
09-局部变量.c
void test1(void); // 全局函数声明
int m = 4456;
int main0901(void)
{
int i = 10903;
for (size_t j = 0; j < 10; j++)
{
printf("j = %d\n", j);
//test1();
}
printf("i 2 = %d\n", i);
system("pause");
return EXIT_SUCCESS;
}
10-申请堆空间.c
int main1001(void)
{
//int arr[1000000] = {10, 20, 40};
int *p = (int *)malloc(sizeof(int) * 10);
//char *str = (char *)malloc(sizeof(char)*10);
if (p == NULL)
{
printf("malloc error\n");
return -1;
}
char *tmp = p; // 记录malloc返回的地址值。用于free
// 写数据到 malloc 空间。
for (size_t i = 0; i < 10; i++)
{
p[i] = i + 10;
}
// 读出malloc空间中的数据
//for (size_t i = 0; i < 10; i++)
//{
// printf("%d ", *(p+i));
//}
for (size_t i = 0; i < 10; i++)
{
printf("%d ", *p);
p++;
}
// 释放申请的内存。
free(tmp);
p = NULL;
system("pause");
return EXIT_SUCCESS;
}
11-二级指针malloc空间.c
int main(void)
{
int **p = malloc(sizeof(int *) * 3); // int **p ==> int *p[10]; ==> [ int *, int *, int * ]
for (size_t i = 0; i < 3; i++)
{
p[i] = malloc(sizeof(int) * 5);
}
// 使用空间 -- 写
for (size_t i = 0; i < 3; i++)
{
for (size_t j = 0; j < 5; j++)
{
p[i][j] = i + j;
}
}
// 使用空间 -- 读
for (size_t i = 0; i < 3; i++)
{
for (size_t j = 0; j < 5; j++)
{
printf("%d ", *(*(p+i)+j)); // p[i][j] == *(p+i)[j] == *(*(p+i)+j)
}
printf("\n");
}
// 释放空间时,应先释放内层空间。
for (size_t i = 0; i < 3; i++)
{
free(p[i]); //*(p+i)
p[i] = NULL;
}
// 释放外层空间
free(p);
p = NULL;
system("pause");
return EXIT_SUCCESS;
}
01-结构体定义及初始化.c
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
struct student {
int age;
char name[10];
int num;
}obj1, obj2;
struct {
int age;
char name[10];
int num;
}obj, *obj4, obj5 = { 100, "abc", 666 };
int main0102(void)
{
obj4 = &obj5;
printf("%x\n", obj5.name[0]);
(*obj4).age = 200;//obj4->age = 200;
strcpy((*obj4).name,"200");
(*obj4).num = 200;
printf("age=%d, name=%s, num=%d\n", obj4->age, obj4->name, obj4->num);
printf("age=%d, |%s|, num=%d\n", (&obj5)->age, (&obj5)->name, (&obj5)->num);
system("pause");
return EXIT_SUCCESS;
}
int main0101(void)
{
struct student stu = { 18, "afei", 97 };
struct student stu2;
stu2.age = 17;
strcpy(stu2.name, "andy");//stu2.name = "andy";
stu2.num = 99;
printf("age = %d, name=%s, num= %d\n", stu2.age, stu2.name, stu2.num);
printf("age = %d, name=%s, num= %d\n", stu.age, stu.name, stu.num);
system("pause");
return EXIT_SUCCESS;
}
02-结构体数组.c
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
struct student {
int age;
char name[10];
int num;
};
int main02(void)
{
struct student arr[5] = { 10, "andy", 10 ,11, "lucy", 11 ,12, "lily", 12 ,13, "mike", 13 ,14, "marry", 14 };
int n = sizeof(arr) / sizeof(arr[0]);
int sum = 0;
for (size_t i = 0; i < n; i++)
{
sum += arr[i].age;
}
printf("avg age = %d\n", sum / n);
system("pause");
return EXIT_SUCCESS;
}
int main0201(void)
{
struct student arr[5] = {
{ 10, "andy", 10 },
{ 11, "lucy", 11 },
{ 12, "lily", 12 },
{ 13, "mike", 13 },
{ 14, "marry", 14 }
};
int n = sizeof(arr) / sizeof(arr[0]);
for (size_t i = 0; i < n; i++)
{
printf("age=%d, name=%s, num=%d\n", arr[i].age, arr[i].name, arr[i].num);
}
printf("\n");
system("pause");
return EXIT_SUCCESS;
}
int main0203(void)
{
struct student arr2[5] = {
10, "andy", 10 ,
11, "lucy", 11 ,
12, "lily", 12 ,
13, "mike", 13 ,
14, "marry", 14
};
struct student arr[5] = {10, "andy", 10 ,11, "lucy", 11 ,12, "lily", 12 ,13, "mike", 13 ,14, "marry", 14};
int n = sizeof(arr) / sizeof(arr[0]);
for (size_t i = 0; i < n; i++)
{
printf("age=%d, name=%s, num=%d\n", arr[i].age, arr[i].name, arr[i].num);
}
printf("\n");
system("pause");
return EXIT_SUCCESS;
}
int main0202(void)
{
struct student arr[5];
arr[0].age = 19;
strcpy(arr[0].name, "1111");
arr[0].num = 19;
(*(arr+1)).age = 191;
strcpy((*(arr + 1)).name, "2222");
(*(arr + 1)).num = 192;
(arr + 2)->age = 193;
strcpy((arr + 2)->name, "333");
(arr + 2)->num = 192;
struct student *p = arr;
(*(p + 3)).age = 194;
strcpy((*(p + 3)).name, "444");
(*(p + 3)).num = 192;
(p + 4)->age = 196;
strcpy((p + 4)->name, "444");
(p + 4)->num = 192;
int n = sizeof(arr) / sizeof(arr[0]);
for (size_t i = 0; i < n; i++)
{
printf("age=%d, name=%s, num=%d\n", arr[i].age, arr[i].name, arr[i].num);
}
printf("\n");
system("pause");
return EXIT_SUCCESS;
}
03-结构体嵌套.c
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
struct person {
int age;
char name[10];
};
struct student {
struct person man;
int score;
};
int main0302(void)
{
struct student stu = { 18, 21, "BBB" };
printf("age = %d\n", (&stu)->man.age);
printf("name = %s\n", (&stu)->man.name);
printf("score = %d\n", (&stu)->score);
system("pause");
return EXIT_SUCCESS;
}
int main0301(void)
{
struct student stu;
stu.man.age = 16;
strcpy(stu.man.name, "zhangsan");
stu.score = 61;
printf("age = %d\n", (&stu)->man.age);
printf("name = %s\n", (&stu)->man.name);
printf("score = %d\n", (&stu)->score);
struct student *p = &stu;
p->man.age = 18;
strcpy(p->man.name, "AAA");
p->score = 100;
printf("age = %d\n", (*p).man.age);
printf("name = %s\n", (&(p->man))->name);
printf("score = %d\n", p->score);
system("pause");
return EXIT_SUCCESS;
}
04-结构体做函数参数.c
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
struct student
{
int age;
char name[10];
int score;
short num;
};
void func(struct student stu)
{
printf("func stu: age = %d, name= %s\n", stu.age, stu.name);
printf("func stu: score = %d, num= %d\n", stu.score, stu.num);
stu.age = 100;
strcpy(stu.name, "super man");
stu.num = 666;
stu.score = 101;
printf("2 func stu: age = %d, name= %s\n", stu.age, stu.name);
printf("2 func stu: score = %d, num= %d\n", stu.score, stu.num);
}
void func2(struct student *stu)
{
printf("func stu: age = %d, name= %s\n", stu->age, stu->name);
printf("func stu: score = %d, num= %d\n", stu->score, stu->num);
stu->age = 100;
strcpy(stu->name, "super man");
stu->num = 666;
stu->score = 101;
printf("2 func stu: age = %d, name= %s\n", stu->age, stu->name);
printf("2 func stu: score = %d, num= %d\n", stu->score, stu->num);
}
struct student func3(struct student stu)
{
printf("func stu: age = %d, name= %s\n", stu.age, stu.name);
printf("func stu: score = %d, num= %d\n", stu.score, stu.num);
stu.age = 100;
strcpy(stu.name, "super man");
stu.num = 666;
stu.score = 101;
printf("2 func stu: age = %d, name= %s\n", stu.age, stu.name);
printf("2 func stu: score = %d, num= %d\n", stu.score, stu.num);
return stu;
}
int main0401(void)
{
struct student stu1 = {15, "ABC", 67, 99};
struct student stu2 = stu1;
//func(stu2); // 实参 给 形参 赋值
//func2(&stu2);
stu2 = func3(stu2);
printf("stu2: age = %d, name= %s\n", stu2.age, stu2.name);
printf("stu2: score = %d, num= %d\n", stu2.score, stu2.num);
system("pause");
return EXIT_SUCCESS;
}
05-含有指针成员的结构体.c
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
struct student {
int age;
char *name; // char name[10]; // 栈
int num;
};
void init_struct(struct student **p)
{
*p = malloc(sizeof(struct student)); // 先申请外层
if (p == NULL) {
printf("malloc error");
return ;
}
(p)->age = 10;
(p)->name = malloc(sizeof(char)10); // 再申请内层
strcpy((p)->name, "hello");
(p)->num = 100;
}
int main0503(void)
{
struct student *p = NULL;
p = malloc(sizeof(struct student)); // 先申请外层空间
p->age = 100;
p->name = malloc(sizeof(char)*10); // 再申请内层空间
strcpy(p->name, "world");
p->num = 20;
printf("age = %d, name=%s, num = %d\n", p->age, p->name, p->num);
free(p->name); // 先释放内层
free(p); // 再释放外层
system("pause");
return EXIT_SUCCESS;
}
int main0502(void)
{
struct student *p = NULL;
init_struct(&p);
printf("age = %d, name=%s, num = %d\n", p->age, p->name, p->num);
free(p->name); // 先释放内层
free(p); // 再释放外层
system("pause");
return EXIT_SUCCESS;
}
int main0501(void)
{
struct student stu;
stu.age = 19;
stu.name = malloc(sizeof(char) * 10); // 堆
strcpy(stu.name, "andy"); // stu.name 是 野指针。
stu.num = 10;
printf("age = %d, name= %s, num= %d\n", stu.age, stu.name, stu.num);
free(stu.name);
stu.name = NULL;
system("pause");
return EXIT_SUCCESS;
}
06-结构体数组作为函数参数.c
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
struct student {
int age;
char *name; // char name[10]; // ջ
int num;
};
//void init_arr(struct student stu[5])
//void init_arr(struct student stu[])
void init_arr(struct student *stu, int n)
{
for (size_t i = 0; i < n; i++)
{
stu[i].age = i + 10;
stu[i].name = malloc(10);
strcpy(stu[i].name, "ABC");
stu[i].num = i * 10;
}
}
void print_arr(struct student *stu, int n)
{
for (size_t i = 0; i < n; i++)
{
printf("age = %d\n", stu[i].age);
printf("name = %s\n", stu[i].name);
printf("num = %d\n", stu[i].num);
}
}
int main0601(void)
{
struct student stu[5];
int n = sizeof(stu) / sizeof(stu[0]);
init_arr(stu, n);
print_arr(stu, n);
for (size_t i = 0; i < n; i++)
{
free(stu[i].name);
}
system("pause");
return EXIT_SUCCESS;
}
07-联合体.c
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
union test {
char a;
short b;
int c;
char str[13];
};
int main0701(void)
{
union test t1;
t1.c = 0x87654321;
printf("&t1 = %p\n", &t1);
printf("&t1.a = %p\n", &(t1.a));
printf("&t1.b = %p\n", &(t1.b));
printf("&t1.c = %p\n", &(t1.c));
printf("a = %x\n", t1.a);
printf("b = %x\n", t1.b);
printf("c = %x\n", t1.c);
t1.b = 0x3A;
printf("----------------\na = %x\n", t1.a);
printf("b = %x\n", t1.b);
printf("c = %x\n", t1.c);
printf("sizeof(t1) = %u\n", sizeof(t1));
system("pause");
return EXIT_SUCCESS;
}
08-枚举.c
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
enum color { red, black, blue = 10, yellow, pink, green };
int main08(void)
{
int flg = yellow;
if (flg == 3)
printf("flg = yellow\n");
system("pause");
return EXIT_SUCCESS;
}
09-typedef.c
typedef long long int32;
typedef struct student {
int32 a;
int32 b;
int32 c;
int32 d;
int32 e;
int32 f;
}stu_t; // 给 struct student 类型起了一个别名: stu_t;
int main09(void)
{
struct student stu;
stu_t s1;
s1.a = 10;
s1.b = 20;
system("pause");
return EXIT_SUCCESS;
}
共用体和联合体:
union test {
char ch;
short sh;
int var;
};
联合体,内部所有成员变量地址一致。等同于整个联合体的地址。
联合体的大小,是内部成员变量中,最大的那个成员变量的大小。(对齐)
修改其中任意一个成员变量的值,其他成员变量会随之修改。
枚 举:
enum color { 枚举常量 };
enum color { red, green, blue, black, pink, yellow };
枚举常量: 是整型常量。不能是浮点数。可以是负值。 默认初值从 0 开始,后续常量较前一个常量 +1.
可以给任意一个常量赋任意初值。后续常量较前一个常量 +1
-----------------------
读写文件与printf、scanf关联
printf -- 屏幕 -- 标准输出
scanf -- 键盘 -- 标准输入
perror -- 屏幕 -- 标准错误
系统文件:
标准输入 -- stdin -- 0
标准输出 -- stdout -- 1
标准错误 -- stderr -- 2
应用程序启动时,自动被打开,程序执行结束时,自动被关闭。 ---- 隐式回收。
1s = 1000ms
1ms = 1000us
1us == 1000ns
文件指针和普通指针区别:
FILE *fp = NULL;
借助文件操作函数来改变 fp 为空、野指针的状况。 fopen(); --> 相当于 fp = malloc();
操作文件, 使用文件读写函数来完成。 fputc、fgetc、fputs、fgets、fread、fwrite
文件分类:
设备文件:
屏幕、键盘、磁盘、网卡、声卡、显卡、扬声器...
磁盘文件:
文本文件: ASCII
二进制文件: 0101 二进制编码
文件操作一般步骤:
1. 打开文件 fopen() --》 FILE *fp;
2. 读写文件 fputc、fgetc、fputs、fgets、fread、fwrite
3. 关闭文件 fclose()
打开、关闭文件函数:
FILE * fopen(const char * filename, const char * mode);
参1:待打开文件的文件名(访问路径)
参2:文件打开权限:
"r": 只读方式打开文件, 文件不存在,报错。存在,以只读方式打开。
"w": 只写方式打开文件, 文件不存在,创建一个空文件。文件如果存在,清空并打开。
"w+":读、写方式打开文件,文件不存在,创建一个空文件。文件如果存在,清空并打开。
"r+":读、写方式打开文件, 文件不存在,报错。存在,以读写方式打开。
"a": 以追加的方式打开文件。
"b": 操作的文件是一个二进制文件(Windows)
返回值:成功:返回打开文件的文件指针
失败:NULL
int fclose(FILE * stream);
参1:打开文件的fp(fopen的返回值)
返回值:成功 :0, 失败: -1;
文件访问路径:
绝对路径:
从系统磁盘的 根盘符开始,找到待访问的文件路径
Windows书写方法:
1)C:\\Users\\afei\\Desktop\\06-文件分类.avi
2)C:/Users/afei/Desktop/06-文件分类.avi --- 也使用于Linux。
相对路径:
1)如果在VS环境下,编译执行(Ctrl+F5),文件相对路径是指相对于 day10.vcxproj 所在目录位置。
2)如果是双击 xxx.exe 文件执行,文件的相对路径是相对于 xxx.exe 所在目录位置。
按字符写文件 fputc:
int fputc(int ch, FILE * stream);
参1:待写入的 字符
参2:打开文件的fp(fopen的返回值)
返回值: 成功: 写入文件中的字符对应的ASCII码
失败: -1
练习:写26个英文字符到文件中。
按字符读文件 fgetc
int fgetc(FILE * stream);
参1:待读取的文件fp(fopen的返回值)
返回值: 成功:读到的字符对应的ASCII码
失败: -1
文本文件的结束标记: EOF ---》 -1
feof()函数:
int feof(FILE * stream);
参1: fopen的返回值
返回值: 到达文件结尾--》非0【真】
没到达文件结尾--》0【假】
作用:
用来判断到达文件结尾。 既可以判断文本文件。也可以判断 二进制文件。
特性:
要想使用feof()检测文件结束标记,必须在该函数调用之前,使用读文件函数。
feof()调用之前,必须有读文件函数调用。
fgets()函数:
获取一个字符串, 以\n作为结束标记。自动添加 \0. 空间足够大 读\n, 空间不足舍弃\n, 必须有\0。
char * fgets(char * str, int size, FILE * stream);
char buf[10]; hello --> hello\n\0
返回值: 成功: 读到的字符串
失败: NULL
fputs()函数:
写出一个字符串,如果字符串中没有\n, 不会写\n。
int fputs(const char * str, FILE * stream);
返回值: 成功: 0
失败: -1
练习: 获取用户键盘输入,写入文件。
假定:用户写入“:wq”终止接收用户输入,将之前的数据保存成一个文件。
FILE *fp = fopen("test07.txt", "w");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
char buf[4096] = {0};
while (1)
{
fgets(buf, 4096, stdin);
if (strcmp(buf, ":wq\n") == 0) // 实际 fgets 读到的是“:wq\n”
{
break;
}
fputs(buf, fp);
}
fclose(fp);
练习: 文件版四则运算:
1. 封装 write_file 函数,将4则运算表达式写入。
FILE * fp = fopen("w");
fputs("10/4=\n", fp);
fputs("10+4=\n", fp);
....
fputs("10*4=\n", fp);
2. 封装 read_file 函数, 将4则运算表达式读出,拆分,运算,写回。
1) 读出:
FILE * fp = fopen("r");
while (1) {
fgets(buf, sizeof(buf), fp); // buf中存储的 4则运算表达式
}
2) 拆分:
sscanf(buf, "%d%c%c=\n", &a, &ch, &b); // 得到运算数, 运算符
3) 根据运算符,得到运算结果
switch(ch) {
case '+':
a+b;
}
4) 拼接 结果到 运算式 上
char result[1024];
sprintf(reuslt, "%d%c%d=%d\n", a, ch, b, a+b); // reuslt 中包含带有结果的 运算式。
5)将 多个带有结果的运算 拼接成一个字符串。
char sum_ses[4096]; // 存总的字符串 -- "10/2=5\n10*3=30\n4+3=7\n8-6=2\n"
strcat(sum_ses,reuslt); // 在while中循环拼接
6) 重新打开文件, 清空原有 4则运算表达式
fclose(fp);
fp = fopen("w");
7) 将 拼接成一个字符串。写入到空的文件中
fputs(sum_res);
10/2= fgets(buf, 4096, 文件fp) --->"10/2=\n" --> 10 / 2 sscanf(buf, "%d%c%d=\n", &a, &c, &b); -> a=10, b=2, c='/'
10*3=
4+3=
8-6=
switch (c) {
case '/':
a / b;
break;
case '+':
a + b;
break;
....
}
fopen("", "w");
char result[]; sprintf()/strcat() --> "10/2=5\n10*3=30\n4+3=7\n8-6=2\n" --> fputs(result, fp)
=====>
10/2=5
10*3=30
4+3=7
8-6=2
01-联合体和枚举.c
typedef union test {
char ch;
short sh;
int a;
}test_t;
int main0101(void)
{
test_t obj;
obj.a = 0x87654321;
printf("&obj = %p\n", &obj);
printf("&obj.ch = %p\n", &obj.ch);
printf("&obj.sh = %p\n", &obj.sh);
printf("&obj.a = %p\n", &obj.a);
printf("sizeof(test_t) = %u\n", sizeof(test_t));
printf("a = 0x%x\n", obj.a);
printf("sh = 0x%x\n", obj.sh);
printf("ch = 0x%x\n", obj.ch);
obj.ch = 0xFF;
printf("a = 0x%x\n", obj.a);
printf("sh = 0x%x\n", obj.sh);
printf("ch = 0x%x\n", obj.ch);
system("pause");
return EXIT_SUCCESS;
}
enum color { red, green = -5, blue, black, pink = 18, yellow };
int main0102(void)
{
int flg = 2;
// ......
if (flg == blue)
{
printf("blue is 2\n");
}
else
{
printf("blue is not 2, blue = %d\n", blue);
}
printf("yellow = %d\n", yellow);
system("pause");
return EXIT_SUCCESS;
}
02-系统文件.c
int main0201(void)
{
//fclose(stdout);
printf("hello file\n");
system("pause");
return EXIT_SUCCESS;
}
03-文件的打开和关闭.c
int main0301(void)
{
FILE *fp = NULL;
fp = fopen("test2.txt", "w");
if (fp == NULL)
{
perror("fopen error"); //printf("fopen error\n"); :xxxxxxx
getchar();
return -1;
}
fclose(fp);
printf("------------finish\n");
system("pause");
return EXIT_SUCCESS;
}
04-fputc.c
int main0401(void)
{
char *filename = "test04.txt";
FILE *fp = fopen(filename, "w");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
int ret = fputc('A', fp);
printf("ret = %d\n", ret);
fclose(fp);
printf("---------------finish\n");
system("pause");
return EXIT_SUCCESS;
}
int main0402(void)
{
char *filename = "test04.txt";
int ret = 0;
FILE *fp = fopen(filename, "w");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
char ch = 'a';
while (ch <= 'z')
{
ret = fputc(ch, fp);
if (ret == -1)
{
perror("fputc eror");
return -1;
}
ch++;
}
system("pause");
return EXIT_SUCCESS;
}
int main0403(void)
{
char *buf = "abcdefghijklmnopqrstuvwxyz";
char *filename = "test04.txt";
int ret = 0;
FILE *fp = fopen(filename, "w");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
int n = strlen(buf);
for (size_t i = 0; i < n; i++)
{
ret = fputc(buf[i], fp);
if (ret == -1)
{
perror("fputc eror");
return -1;
}
}
fclose(fp);
system("pause");
return EXIT_SUCCESS;
}
05-fgetc.c
void write_file()
{
FILE *fp = fopen("05test.txt", "w");
if (fp == NULL)
{
perror("fopen error");
return ;
}
fputc('a', fp);
fputc('b', fp);
fputc('c', fp);
fputc('d', fp);
fclose(fp);
}
void read_file()
{
char ch = 0;
FILE *fp = fopen("05test.txt", "r");
if (fp == NULL)
{
perror("fopen error");
return;
}
while (1)
{
ch = fgetc(fp);
if (ch == EOF)
{
break;
}
printf("%d\n", ch);
}
fclose(fp);
}
int main0501(void)
{
//write_file();
read_file();
system("pause");
return EXIT_SUCCESS;
}
06-feof函数.c
void read_file06()
{
char ch = 0;
FILE *fp = fopen("06test.txt", "r");
if (fp == NULL)
{
perror("fopen error");
return;
}
while (1)
{
ch = fgetc(fp);if (feof(fp))
{
break;
}
printf("%d\n", ch);
}
fclose(fp);
}
void test_feof()
{
FILE *fp = fopen("06test.txt", "r");
if (fp == NULL)
{
perror("fopen error");
return ;
}
while (1)
{
printf("没有到达文件结尾\n");
fgetc(fp); // 一次读一个字符,读到字符直接丢弃。
if (feof(fp))
{
break;
}
}
fclose(fp);
}
void write_file06()
{
FILE *fp = fopen("06test.txt", "w");
if (fp == NULL)
{
perror("fopen error");
return;
}
fputc('a', fp);
fputc('b', fp);
fputc(-1, fp);
fputc('c', fp);
fputc('d', fp);
fputc('\n', fp);
fclose(fp);
}
int main0601(void)
{
//write_file06();
//read_file06();
test_feof();
system("pause");
return EXIT_SUCCESS;
}
07-fgets和fputs.c
int main0701(void)
{
FILE *fp = fopen("test07.txt", "w");
if (fp == NULL)
{
perror("fopen error");
return -1;
}
char buf[4096] = {0};
while (1)
{
fgets(buf, 4096, stdin);
if (strcmp(buf, ":wq\n") == 0)
{
break;
}
fputs(buf, fp);
}
fclose(fp);
system("pause");
return EXIT_SUCCESS;
}
08-文件版4则运算.c
void write_file08()
{
FILE *fp = fopen("test08.txt", "w");
if (fp == NULL)
{
perror("fopen error");
return;
}
fputs("10/2=\n", fp);
fputs("10*3=\n", fp);
fputs("4-2=\n", fp);
fputs("10+2=\n", fp);
fclose(fp);
}
int calc(char ch, int a, int b)
{
switch (ch)
{
case '/':
return a / b;
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a *b;
default:
break;
}
}
void read_file08()
{
char buf[4096] = {0};
char result[4096] = {0};
char sum_res[4096] = {0};
int a, b, ret;
char ch;
FILE *fp = fopen("test08.txt", "r");
if (fp == NULL)
{
perror("fopen error");
return;
}
while (1)
{
fgets(buf, 4096, fp); //buf = "10/2=\n\0";
if (feof(fp))
{
break;
}
sscanf(buf, "%d%c%d=\n", &a, &ch, &b); // a:10, ch:'/' b: 2sprintf(result, "%d%c%d=%d\n", a, ch, b, calc(ch, a, b)); // 10 / 2 = 5;
strcat(sum_res, result);
}
fclose(fp); // 将 只有表达式没有结果的文件关闭。
fp = fopen("test08.txt", "w"); // 清空 只有表达式没有结果的文件
if (fp == NULL)
{
perror("fopen error");
return;
}
fputs(sum_res, fp); // 将 既有表达式又有结果的字符串写到文件中。
fclose(fp);
}
int main(void)
{
write_file08();
getchar();
read_file08();
system("pause");
return EXIT_SUCCESS;
}
printf --- sprintf --- fprintf:
变参函数:参数形参中 有“...”, 最后一个固参通常是格式描述串(包含格式匹配符), 函数的参数个数、类型、顺序由这个固参决定。
printf("hello");
printf("%s", "hello");
printf("ret = %d+%d\n", 10, 5);
printf("%d = %d%c%d\n", 10+5, 10, '+', 5); --> 屏幕
char buf[1024]; //缓冲区
sprintf(buf, "%d = %d%c%d\n", 10+5, 10, '+', 5); --> buf 中
FILE * fp = fopen();
fprintf(fp, "%d = %d%c%d\n", 10+5, 10, '+', 5); --> fp 对应的文件中
scanf --- sscanf --- fscanf
scanf("%d", &m); 键盘 --> m
char str[] = "98";
sscanf(str, "%d", &m); str --> m
FILE * fp = fopen("r");
fscanf(fp, "%d", &m); fp指向的文件中 --> m
fprintf()函数: ---> 将数据按指定的格式写进文件中
写
int fprintf(FILE * stream, const char * format, ...);
fscanf()函数:---> 从文件中读取指定格式的数据到内存中
读
int fscanf(FILE * stream, const char * format, ...);
成功:正确匹配的个数。
失败: -1
1) 边界溢出。 存储读取的数据空间。在使用之前清空。
2)fscanf函数,每次在调用时都会判断下一次调用是否匹配参数2, 如果不匹配提前结束读文件。(feof(fp) 为真)。
练习:文件版排序
生成随机数,写入文件。将文件内乱序随机数读出,排好序再写回文件。
fgetc --- fputc
fgets --- fputs
fprintf -- fscanf 默认处理文本文件。
fwrite()函数: 既可处理以文本文件。也处理二进制文件。
写出数据到文件中。
stu_t stu[4] = { ...... };
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
参1:待写出的数据的地址
参2:待写出数据的大小
参3:写出的个数 -- 参2 x 参3 = 写出数据的总大小。
参4:文件
返回值: 成功:永远是 参3 的值。 --- 通常将参2 传 1. 将参3传实际写出字节数。
失败:0
fread()函数:
从文件fp中读出数据。
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参1:读取到的数据存储的位置
参2:一次读取的字节数
参3:读取的次数 -- 参2 x 参3 = 读出数据的总大小
参4:文件
返回值: 成功:参数3. --- 通常将参2 传 1. 将参3传欲读出的字节数。
0:读失败 -- 到达文件结尾 -- feof(fp)为真。
练习:大文件拷贝
已知一个任意类型的文件,对该文件复制,产生一个相同的新文件。
1. 打开两个文件, 一个“r”, 另一“w”
2. 从r中 fread , fwrite到 w 文件中。
3. 判断到达文件结尾 终止。
4. 关闭。
注意: 在windows下,打开二进制文件(mp3、mp4、avi、jpg...)时需要使用“b”。如:“rb”、“wb”
随机位置 读:
文件读写指针。在一个文件内只有一个。
fseek():
int fseek(FILE *stream, long offset, int whence);
参1:文件
参2:偏移量(矢量: + 向后, - 向前)
参3: SEEK_SET:文件开头位置
SEEK_CUR:当前位置
SEEK_END:文件结尾位置
返回值: 成功:0, 失败: -1
ftell():
获取文件读写指针位置。
long ftell(FILE *stream);
返回:从文件当前读写位置到起始位置的偏移量。
借助 ftell(fp) + fseek(fp, 0, SEEK_END); 来获取文件大小。
rewind():
回卷文件读写指针。 将读写指针移动到起始位置。
void rewind(FILE *stream);
Linux和windows文件区别:
1)对于二进制文件操作, Windows 使用“b”, Linux下二进制和文本没区别。
2)windows下,回车 \r, 换行 \n。 \r\n , Linux下 回车换行\n
3) 对文件指针,先写后读。windows和Linux效果一致。
先读后写。Linux无需修改。windows下需要在写操作之前添加 fseek(fp, 0, SEEK_CUR); 来获取文件读写指针,使之生效。
获取文件状态:
打开文件,对于系统而言,系统资源消耗较大。
int stat(const char *path, struct stat *buf);
参1: 访问文件的路径
参2: 文件属性结构体
返回值: 成功: 0, 失败: -1;
删除、重命名文件:
int remove(const char *pathname); 删除文件。
int rename(const char *oldpath, const char *newpath); 重名文件
缓冲区刷新:
标准输出-- stdout -- 标准输出缓冲区。 写给屏幕的数据,都是先存缓冲区中,由缓冲区一次性刷新到物理设备(屏幕)
标准输入 -- stdin -- 标准输入缓冲区。 从键盘读取的数据,直接读到 缓冲区中, 由缓冲区给程序提供数据。
预读入、缓输出。
行缓冲:printf(); 遇到\n就会将缓冲区中的数据刷新到物理设备上。
全缓冲:文件。 缓冲区存满, 数据刷新到物理设备上。
无缓冲:perror。 缓冲区中只要有数据,就立即刷新到物理设备。
文件关闭时, 缓冲区会被自动刷新。 隐式回收:关闭文件、刷新缓冲区、释放malloc
手动刷新缓冲区: 实时刷新。
int fflush(FILE *stream);
成功:0
失败:-1
01-sprintf 和 sscanf.c
void write_file()
{
FILE *fp = fopen("abc.c", "w");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
fprintf(fp, "%d\n", 10);
fprintf(fp, "%d\n", 8);
fprintf(fp, "%d\n", 6);
fclose(fp);
}
void read_file()
{
int a;
FILE *fp = fopen("abc.c", "r");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
fscanf(fp, "%d\n", &a);
printf("%d\n" , a);
fscanf(fp, "%d\n", &a);
printf("%d\n", a);
fscanf(fp, "%d\n", &a);
printf("%d\n", a);
a = 0;
fscanf(fp, "%d\n", &a);
printf("%d\n", a);
fclose(fp);
}
// fscanf 循环读文件
void read_file2()
{
int a;
FILE *fp = fopen("abc.c", "r");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
while (1)
{
fscanf(fp, "%d\n", &a); // 读
printf("%d\n", a);
if (feof(fp)) // 真-- 文件结尾
break;
}
fclose(fp);
}
// fgets 循环读文件
void read_file3()
{
char buf[1024];
FILE *fp = fopen("abc.c", "r");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
while (1)
{
memset(buf , 0, 1024);
fgets(buf, 1024, fp);// 读 \n
if (feof(fp)) // 真-- 文件结尾
break;
printf("%d\n", buf[0]);
}
fclose(fp);
}
int main0101(void)
{
//write_file();
read_file3();
system("pause");
return EXIT_SUCCESS;
}
int main(void)
{
FILE *fp = fopen("test0101.txt", "r");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
int a;
char ch;
char str[10];
int ret = fscanf(fp, "%d %c %s", &a, &ch, str);
printf("ret = %d\n", ret);
fclose(fp);
system("pause");
return EXIT_SUCCESS;
}
02-文件版排序.c
#include
#include
#include
void write_rand()
{
FILE *fp = fopen("test02.txt", "w");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
srand(time(NULL)); // 随机数种子
for (size_t i = 0; i < 10; i++)
{
fprintf(fp, "%d\n", rand() % 100); // 将生成的随机数写入文件
}
fclose(fp);
}
void BubbleSort(int * src, int len)
{
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - 1 - i; j++)
{
if (src[j] > src[j + 1])
{
int temp = src[j];
src[j] = src[j + 1];
src[j + 1] = temp;
}
}
}
}
void read_rand02()
{
int arr[10], i = 0;
FILE *fp = fopen("test02.txt", "r");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
while (1)
{
fscanf(fp, "%d\n", &arr[i]);// 从文件中读取一个随机数,存入数组arr
i++;
if (feof(fp)) // 先存储,后判断,防止最后一个元素丢失
break;
}
BubbleSort(arr, sizeof(arr)/sizeof(arr[0])); // 对读取到的乱序数组排序
fclose(fp); // 关闭文件
fp = fopen("test02.txt", "w"); // 重新w方式打开文件, 清空原未排序文件。
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
for (size_t i = 0; i < 10; i++)
fprintf(fp, "%d\n", arr[i]); // 写排好序的数组到文件
fclose(fp);
}
int main0201(void)
{
write_rand();
getchar();
read_rand02();
system("pause");
return EXIT_SUCCESS;
}
03-fwrite 和 fread.c
typedef struct student {
int age;
char name[10];
int num;
} stu_t;
void write_struct()
{
stu_t stu[4] = {
18, "afei", 10,
20, "andy", 20,
30, "lily", 30,
16, "james", 40
};
FILE *fp = fopen("test03.txt", "w");
if (!fp)
{
perror("fopen error");
return -1;
}
int ret = fwrite(&stu[0], 1, sizeof(stu_t) * 4, fp);
if (ret == 0)
{
perror("fwrite error");
return -1;
}
printf("ret = %d\n", ret);
fclose(fp);
}
// 一次读一个元素。
void read_struct()
{
FILE *fp = fopen("test03.txt", "r");
if (!fp)
{
perror("fopen error");
return -1;
}
stu_t s1;
int ret = fread(&s1, 1, sizeof(stu_t), fp);
printf("ret = %d\n", ret);
printf("age = %d, name=%s, num = %d\n", s1.age, s1.name, s1.num);
fclose(fp);
}
// 读所有元素
void read_struct2()
{
FILE *fp = fopen("test03.txt", "r");
if (!fp)
{
perror("fopen error");
return -1;
}
stu_t s1[10]; // stu_t *s1 = malloc(sizeof(stu_t) * 1024);
int i = 0;
while (1)
{
int ret = fread(&s1[i], 1, sizeof(stu_t), fp);
//if (ret == 0) // 替代feof()函数来判断读到文件结尾。
if (feof(fp))
{
break;
}
i++;
printf("age = %d, name=%s, num = %d\n", s1[i].age, s1[i].name, s1[i].num);
}
fclose(fp);
}
int main0301(void)
{
//write_struct();
read_struct2();
system("pause");
return EXIT_SUCCESS;
}
04-大文件拷贝.c
void myfile_cp()
{
FILE *rfp = fopen("C:\itcast\08-fread函数.avi", "rb");
FILE *wfp = fopen("C:\itcast\mycopy.avi", "wb");
char buf[4096] = {0}; // 缓冲区。
int ret = 0;
while (1)
{
memset(buf, 0, sizeof(buf));
ret = fread(buf, 1, sizeof(buf), rfp);
if (ret == 0)
{
break;
}
printf("ret = %d\n", ret);
fwrite(buf, 1, ret, wfp);
}
fclose(wfp);
fclose(rfp);
}
int main0401(void)
{
myfile_cp();
printf("---------------------finish\n");
system("pause");
return EXIT_SUCCESS;
}
05-随机读文件.c
typedef struct student {
int age;
char name[10];
int num;
} stu_t;
int main0501(void)
{
stu_t stu[4] = {
18, "afei", 10,
20, "andy", 20,
30, "lily", 30,
16, "james", 40
};
stu_t s1;
FILE *fp = fopen("test05.txt", "wb+");
if (!fp) // fp == NULL
{
perror("fopen error");
return -1;
}
int ret = fwrite(&stu[0], 1, sizeof(stu), fp); // 以二进制形式写入,
printf("ret = %d\n", ret);
fseek(fp, sizeof(stu_t)*2, SEEK_SET); // 从文件起始位置,向后偏移一个stu结构体
ret = fread(&s1, 1, sizeof(s1), fp);
printf("ret = %d\n", ret);
printf("1 age= %d, name=%s, num=%d\n", s1.age, s1.name, s1.num);
int len = ftell(fp); // 获取文件当前读写指针位置,到文件起始位置的偏移量。
printf("len = %d\n", len);
rewind(fp); // 将文件读写指针回卷到起始。
ret = fread(&s1, 1, sizeof(s1), fp);
printf("2 age= %d, name=%s, num=%d\n", s1.age, s1.name, s1.num);
// 获取文件大小。
fseek(fp, 0, SEEK_END); // 将文件读写指针放到文件结尾。
len = ftell(fp);
printf("文件大小为:%d\n", len);
fclose(fp);
system("pause");
return EXIT_SUCCESS;
}
int main0502(void)
{
FILE *fp = fopen("test0501.txt", "w+"); // "r+"
int ret = fputs("11111", fp);
printf("ret 1 = %d\n", ret); // 0 表示成功。
ret = fputs("22222", fp);
printf("ret 2 = %d\n", ret);
ret = fputs("33333", fp);
printf("ret 3 = %d\n", ret);
char buf[1024] = { 0 };
//fseek(fp, 5 * 2, SEEK_SET); // 改变读写指针位置。
rewind(fp); // 起始位置。
char *ptr = fgets(buf, 1024, fp);
if (ptr == NULL)
printf("ptr == NULL \n");
printf("fgets ptr = %s\n", ptr);
printf("buf = %s\n", buf);
fclose(fp);
system("pause");
return EXIT_SUCCESS;
}
#include
#include
#include
int main0503(int argc, char *argv[])
{
FILE *fp = fopen("test1.txt", "r+");
char buf[6] = { 0 };
char *ptr = fgets(buf, 6, fp);
printf("buf=%s, ptr=%s\n", ptr, buf);
fseek(fp, 0, SEEK_CUR);
int ret = fputs("AAAAA", fp);
printf("ret = %d\n", ret);
fclose(fp);
system("pause");
return 0;
}
06-获取文件属性-大小.c
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
/*
FILE *fp = fopen("test05.txt", "r");
fseek(fp, 0, SEEK_END);
int len = ftell(fp);
printf("文件大小:%d\n", len);
fclose(fp);
*/
int main0602(void)
{
struct stat buf;
int ret = stat("test05.txt", &buf); // 传出参数:在函数调用结束时,充当函数返回值。
printf("文件大小:%d\n", buf.st_size); // 不打开文件,获取文件大小。
system("pause");
return EXIT_SUCCESS;
}
07-刷新缓冲区.c
int main0701(void)
{
FILE *fp = fopen("test07.txt", "w+");
if (!fp)
{
perror("fopen error");
return -1;
}
char m = 0;
while (1)
{
scanf("%c", &m);
if (m == ':')
{
break;
}
fputc(m, fp);
fflush(fp); // 手动刷新文件缓冲到物理磁盘。
}
// 当文件关闭时,会自动刷新缓冲区。
fclose(fp);
system("pause");
return EXIT_SUCCESS;
}
源文件 -- main.c
#define _CRT_SECURE_NO_WARNINGS
#include "snake.h" // 引入自定义头文件
int main(void)
{
// 去除光标。
CONSOLE_CURSOR_INFO cci;
cci.dwSize = sizeof(cci);
cci.bVisible = FALSE; // TRUE :
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
srand(time(NULL)); // 播种随机数种子。
initSnake(); // 初始化蛇
initFood(); // 初始化食物
initWall(); // 画墙
initUI(); // 画蛇和食物
playGame(); // 启动游戏
showScore(); // 打印分数
system("pause");
return EXIT_SUCCESS;
}
void showScore(void)
{
// 将光标默认位置移动至 不干扰游戏的任意位置。
COORD coord;
coord.X = 0;
coord.Y = HIGH + 2;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
printf("Game Over!!!\n");
printf("成绩为:%d\n\n\n", score);
}
void initWall(void)
{
for (size_t i = 0; i <= HIGH; i++) // 多行
{
for (size_t j = 0; j <= WIDE; j++) // 一行中的多列
{
if (j == WIDE)
{
printf("|");
}
else if (i == HIGH)
{
printf("_");
}
else
{
printf(" ");
}
}
printf("\n");
}
}
void playGame(void)
{
char key = 'd';
// 判断蛇撞墙
while (snake.body[0].X >= 0 && snake.body[0].X < WIDE
&& snake.body[0].Y >= 0 && snake.body[0].Y < HIGH)
{
// 更新蛇
initUI();// 接收用户按键输入 asdw
if (_kbhit()) { // 为真时,说明用户按下按键。
key = _getch();
}
switch (key)
{
case 'w': kx = 0; ky = -1; break;
case 's': kx = 0; ky = +1; break;
case 'd': kx = +1; ky = 0; break;
case 'a': kx = -1; ky = 0; break;
default:
break;
}
// 蛇头撞身体: 蛇头 == 任意一节身体
for (size_t i = 1; i < snake.size; i++)
{
if (snake.body[0].X == snake.body[i].X
&& snake.body[0].Y == snake.body[i].Y)
{
return; // 游戏结束。
}
}
// 蛇头撞食物
if (snake.body[0].X == food.X && snake.body[0].Y == food.Y)
{
initFood(); // 食物消失
snake.size++; // 身体增长
score += 10; // 加分
sleepSecond -= 100; // 加速
}
// 存储蛇尾坐标
lastX = snake.body[snake.size - 1].X;
lastY = snake.body[snake.size - 1].Y;
// 蛇移动,前一节身体给后一节身体赋值。
for (size_t i = snake.size - 1; i > 0; i--)
{
snake.body[i].X = snake.body[i - 1].X;
snake.body[i].Y = snake.body[i - 1].Y;
}
snake.body[0].X += kx; // 蛇头坐标根据用户按键,修改。
snake.body[0].Y += ky;
Sleep(sleepSecond);
// 清屏
//system("cls");
}
return;
}
// 定义初始化蛇函数
void initSnake(void)
{
snake.size = 2;
snake.body[0].X = WIDE / 2; //蛇头初始化
snake.body[0].Y = HIGH / 2;
snake.body[1].X = WIDE / 2 - 1; // 蛇一节身体初始化
snake.body[1].Y = HIGH / 2;
return;
}
// 初始化界面控件
void initUI(void)
{
COORD coord = {0}; // 光标移动的位置。
// 画蛇
for (size_t i = 0; i < snake.size; i++)
{
coord.X = snake.body[i].X;
coord.Y = snake.body[i].Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);if (i == 0)
putchar('@');
else
putchar('*');
}
// 去除蛇尾
coord.X = lastX;
coord.Y = lastY;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
putchar(' ');
// 画食物
coord.X = food.X;
coord.Y = food.Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
putchar('#');
}
// 食物的初始化函数
void initFood(void)
{
food.X = rand() % WIDE; // 0-59
food.Y = rand() % HIGH; // 0-59
return;
}
头文件 -- snake.h
#ifndef SNAKE_H
#define SNAKE_H
#include
#include
#include
#include
#include
#include
#include
#define WIDE 60 // 宽度
#define HIGH 20 // 高度
// 一个身体的对象
struct BODY {
int X;
int Y;
};
// 定义蛇对象
struct SNAKE {
struct BODY body[WIDE*HIGH];
int size;
}snake; // 一个蛇对象
// 定义食物对象
struct FOOD {
int X;
int Y;
}food1; // 一个食物对象
int score = 0; // 分数
int kx = 0; // 用户按下 asdw 任意一个按键所得到的 坐标值。
int ky = 0;
int lastX = 0; // 蛇尾的坐标。
int lastY = 0;
int sleepSecond = 400;
// 声明函数
void initSnake(void);
void initFood(void);
void initUI(void);
void playGame(void);
void initWall(void);
void showScore(void);
#endif
vim 3 种工作模式:
命令模式:
使用所有输入都被vim当成命令看。
i、a、o、s -- I、A、O、S
文本模式(编辑模式):
在该模式下编辑代码。
末行模式:
“:” 切换为末行模式。
w:保存。 q:退出。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章