C库函数
C标准库链接:
https://www.runoob.com/cprogramming/c-standard-library-stdio-h.html
15、int main(int argc, char *argv[], char *envp[]) 的用法
其实: int main(int argc,char *argv[]) 是 UNIX 和 Linux 中的标准写法,而 int main() 只是 UNIX 及 Linux 默许的用法.
那究竟 argc,argv[] 有何之用呢?下面看个例子 edit.c 就会明白它们的用法了:
- #include <unistd.h>
- #include <stdio.h>
- int main(int argc,char *argv[]){
- if(argc==1 || argc>2) {
- printf("请输入想要编辑的文件名如:./edit fillen");
- }
- if(argc==2) {
- printf("编辑 %sn",argv[1]);
- }
- exit(0)
- }
- 编译该程序:gcc -o edit edit.c
- 运行:./edit
- 结果:请输入想要编辑的文件名如:./edit fille
- 运行:./edit edit.txt
- 结果:编辑 edit.txt
- 看到这里 argc,argv[] 如何用就很明白了,argc 是外部命令参数的个数,argv[] 存放各参数的内容,如上例:执行 ./edit 时,argc 为1, argv[0] 为 ./edit .
- 而执行 ./edit edit.txt 时,argc 的值为 2,argv[0] 为./edit, argv[1] 为 edit.txt .
- 网友回复:简单的说,就是命令行参数!
- argc 是外部命令参数的个数,argv[] 存放各参数的内容,如上例:执行 ./edit 时,argc 为1, argv[0] 为 ./edit .
- 而执行 ./edit edit.txt 时,argc 的值为 2,argv[0] 为 ./edit,argv[1] 为 edit.txt .
- 网友回复:int argc 参数个数
- char** argv 参数数组,,数组大小就是前面那个参数,通过数组下标访问里面存放的内容,例如argv[0],argv[1]
- 网友回复:int main(int argc,char** argv)
- {
- FILE *fp;
- fp = fopen("E:/works/ee/debug/1.txt","r");
- 为什么这个fp指针还是为空了???
- 网友回复:指针使用之前应该进行初始化
11、int main(int argc, char *argv[], char *envp[])
这个赋值过程是编译器完成的,我们只需要读出数据就可以了。
int main(int argc, char *argv[], char *envp[])
main()函数一般用int或者void形的。我比较喜欢用int型定义main。因为在结束的时候可以返回给操作系统一个值以表示执行情况。
参数:
int argc
这个东东用来表示你在命令行下输入命令的时候,一共有多少个参数。比方说你的程序编译后,可执行文件是test.exe
D:\tc2>test
这个时候,argc的值是1
但是
D:\tc2>test.exe myarg1 myarg2
的话,argc的值是3。也就是 命令名 加上两个参数,一共三个参数
char *argv[]
这个东东用来取得你所输入的参数
D:\tc2>test
这个时候,argc的值是1,argv[0]的值是 "test"
D:\tc2>test myarg1 myarg2
这个时候,argc的值是3,argc[0]的值是"test",argc[1]的值是"myarg1",argc[2]的值是"myarg2"。
这个东东一般用来为程序提供非常重要的信息,如:数据文件名,等等。
如:copy a.c b.txt
这个时候,a.c和b.txt就是所谓的“非常重要的信息”。不指定这两个文件,你没法进行拷贝。
当你的程序用到argc和argv这两个参数的时候,可以简单地通过判断argc的值,来看看程序的参数是否符合要求
argv数组中的第一个单元,指向的字符串总是可执行程序的名字,以后的单元指向的字符串依次是程序调用时的参数。
这个赋值过程是编译器完成的,我们只需要读出数据就可以了。
char *envp[]
这个东东相对来说用得比较少。它是用来取得系统的环境变量的。
如:在DOS下,有一个PATH变量。当你在DOS提示符下输入一个命令(当然,这个命令不是dir一类的内部命令)的时候,DOS会首先在当前目录下找这个命令的执行文件。
如果找不到,则到PATH定义的路径下去找,找到则执行,找不到返回Bad command or file name
在DOS命令提示符下键入set可查看系统的环境变量
同样,在UNIX或者LINUX下,也有系统环境变量,而且用得比DOS要多。如常用的$PATH,$USER,$HOME等等。
envp保存所有的环境变量。其格式为(UNIX下)
PATH=/usr/bin;/local/bin;
HOME=/home/shuui
即:
环境变量名=值
DOS下大概也一样。
exit()是程序退出时的返回码,可以用其他程序接收,判断是否正常退出。如exit(-1)认为异常退出。
Examples:
https://www.cnblogs.com/avril/archive/2010/03/22/1691477.html
C语言库- <getopt.h>
1、int getopt_long(argc, argv, short_options, long_options, NULL ) 解析命令行参数
-
int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);
使用GNU C提供的函数getopt、getopt_long、getopt_long_only函数来解析命令行参数。命令行参数可以分为两类,一类是短选项,一类是长选项,
如(ls 命令参数)所示,
-a,-A,-b都表示短选项,
--all,--almost-all, --author都表示长选项。
他们两者后面都可选择性添加额外参数。比如--block-size=SIZE,SIZE便是额外的参数。原文链接:https://blog.csdn.net/qq_33850438/article/details/80172275
(1)argc和argv和main函数的两个参数一致
(2)optstring: 表示短选项字符串
短选项在参数前加一杠"-",
- 形式如“a🅱️💿“,分别表示程序支持的命令行短选项有-a、-b、-c、-d,冒号含义如下:
- (1)只有一个字符,不带冒号——只表示选项, 如-c
- (2)一个字符,后接一个冒号——表示选项后面带一个参数,如-a 100
- (3)一个字符,后接两个冒号——表示选项后面带一个可选参数,即参数可有可无, 如果带参数,则选项与参数直接不能有空格
- 形式应该如-b200
- static const char *short_options = "f:vy:l:r:c:dapⓂ️ut:eg:";
(3)longopts:表示长选项结构体。
结构如下:
长选项在参数前连续加两杠"--",
- (1)name:表示选项的名称,比如daemon,dir,out等。
- (2)has_arg:表示选项后面是否携带参数。该参数有三个不同值,如下:
- a: no_argument(或者是0)时 ——参数后面不跟参数值,eg: --version,--help
- b: required_argument(或者是1)时 ——参数输入格式为:--参数 值 或者 --参数=值。eg:--dir=/home
- c: optional_argument(或者是2)时 ——参数输入格式只能为:--参数=值
- (3)flag:这个参数有两个意思,空或者非空。
- a:如果参数为空NULL,那么当选中某个长选项的时候,getopt_long将返回val值。 eg,可执行程序 --help,getopt_long的返回值为h.
- b:如果参数不为空,那么当选中某个长选项的时候,getopt_long将返回0,并且将flag指针参数指向val值。 eg: 可执行程序 --http-proxy=127.0.0.1:80 那么getopt_long返回值为0,并且lopt值为1。
- (4)val:表示指定函数找到该选项时的返回值,或者当flag非空时指定flag指向的数据的值val。
1.
2. struct option
3. {
4. const char *name; // name:表示选项的名称,比如daemon,dir,out等
5. int has_arg; //表示选项后面是否携带参数 ,0\1\2
6. int *flag;
7. int val; //表示指定函数找到该选项时的返回值
8. };
9. eg:
10. static struct option long_options[] = {
11. {"filename_base", HAS_ARG, 0, 'f'},
12. {"video", NO_ARG, 0, DUMP_VIDEO},
13. {"yuv", HAS_ARG, 0, DUMP_YUV},
14. {"luma", HAS_ARG, 0, DUMP_LUMA},
15. {"raw", HAS_ARG, 0, DUMP_RAW},
16. {"buf_dump", NO_ARG, 0, DUMP_BUF},
17. {"vca_dump", NO_ARG, 0, DUMP_VCA},
18. {"count", HAS_ARG, 0, COUNT},
19. {"yuv_pre", HAS_ARG, 0, DUMP_YUV_PRE},
20. {"pyramid", HAS_ARG, 0, DUMP_PYRAMID},
21. {"use-dma-buf", NO_ARG, 0, USE_DMA_BUF},
22. {"show-pts", HAS_ARG, 0, SHOW_PTS},
23. {"cap-extra-raw", NO_ARG, 0, DUMP_EXTRA_RAW},
24. {"multiple-yuv", HAS_ARG, 0, DUMP_MULTI_YUV},
25. {0, 0, 0, 0}
26. }; // longopts的最后一个元素必须是全0填充,否则会报段错误
27.
(4)longindex:
longindex非空,它指向的变量将记录当前找到参数符合longopts里的第几个元素的描述,即是longopts的下标值。
(5)返回值:
(1)如果短选项找到,那么将返回短选项对应的字符。
(2)如果长选项找到,如果flag(长选项中的第三个值)为NULL,返回val。如果flag不为空,返回0
(3)如果遇到一个选项没有在短字符、长字符里面。或者在长字符里面存在二义性的,返回“?”
(4)如果解析完所有字符没有找到(一般是输入命令参数格式错误,eg: 连斜杠都没有加的选项),返回“-1”
(5)如果选项需要参数,忘了添加参数。返回值取决于optstring,如果其第一个字符是“:”,则返回“:”,否则返回“?”。
(6)全局变量:optarg\optind\opteer\optopt
这些全局变量的使用,
int ch;
ch = getopt_long(argc, argv, short_options, long_options, &option_index)
snprintf(filename, sizeof(filename), "%s", optarg);
//使用了getopt_long()后,在 test_stream –f /mnt 命令执行时,-f 是当前选项,optarg是参数值即指向 /mnt,
- (1)optarg:表示当前选项对应的参数值。
- (2)optind:表示的是下一个将被处理到的参数在argv中的下标值。
- (3)opterr:如果opterr = 0,在getopt、getopt_long、getopt_long_only遇到错误将不会输出错误信息到标准输出流。opterr在非0时,向屏幕输出错误。
- (4)optopt:表示没有被未标识的选项。
注意:
- (1)longopts的最后一个元素必须是全0填充,否则会报段错误
- (2)短选项中每个选项都是唯一的。而长选项如果简写,也需要保持唯一
C 标准库 - <stdlib.h>
1、malloc()
- C 库函数 void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。
- C 库函数 void *calloc(size_t nitems, size_t size) 分配所需的内存空间,并返回一个指向它的指针。malloc 和 calloc 之间的不同点是,malloc 不会设置内存为零,而 calloc 会设置分配的内存为零。
- C 库函数 void *realloc(void *ptr, size_t size) 尝试重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小。
- C 库函数 void free(void *ptr) 释放之前调用 calloc、malloc 或 realloc 所分配的内存空间。
Example 1
这个例子,区别了 malloc 与 calloc ,可以判断malloc分配内存是否成功。
-
f_socket_data = (float *)malloc(total_vpout_length);
-
if (!f_socket_data) { //如果有分配了内存,就不执行此函数。
-
printf("ERROR: Out of memory for f_socket_data!\n");
-
ret = -1;
-
break;
-
}
Example 2
这个例子使用了 malloc realloc free
-
#include <stdio.h>
-
#include <string.h>
-
#include <stdlib.h>
-
int main()
-
{
-
char *str;
-
/* 最初的内存分配 */
-
str = (char *) malloc(15); //使用malloc 需要进行强制类型转换
-
strcpy(str, "runoob");
-
printf("String = %s, Address = %u\n", str, str);
-
/* 重新分配内存 */
-
str = (char *) realloc(str, 25);
-
strcat(str, ".com");
-
printf("String = %s, Address = %u\n", str, str);
-
free(str);
-
return(0);
-
}
-
让我们编译并运行上面的程序,这将产生以下结果:
-
String = runoob, Address = 3662685808
-
String = runoob.com, Address = 3662685808
new和malloc的区别可以从以下几方面进行阐述:
属性上:new/delete是C++关键字需要编译器支持,maollc是库函数,需要添加头文件
最大的区别:new在申请空间的时候会调用构造函数,malloc不会调用
成功返回类型:new操作符申请内存成功时,返回的是对象类型的指针,类型严格与对象匹配,无需进行类型转换,因此new是类型安全性操作符。malloc申请内存成功则返回void*,需要强制类型转换为我们所需的类型
申请失败返回:new在申请空间失败后返回的是错误码bad_alloc,malloc在申请空间失败后会返回NULL
参数:new在申请内存分配时不需要指定内存块大小,编译器会更具类型计算出大小,malloc需要显示的指定所需内存的大小
自定义类型:new会先调operator new函数,申请足够的内存(底层也是malloc实现),然后调用类的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数来释放内存(底层是通过free实现)。malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构函数
重载:C++允许重载new/delete操作符,特别的,布局new的就不需要为对象分配内存,而是指定了一个地址作为内存起始区域,new在这段内存上为对象调用构造函数完成初始化工作,并返回地址。malloc不允许重载。
New 与 delete
如果动态分配了一个数组,但是却用delete p的方式释放,没有用[],则编译时没有问题,运行时也一般不会发生错误,但实际上会导致动态分配的数组没有被完全释放。
牢记,用 new 运算符动态分配的内存空间,一定要用 delete 运算符释放。否则,即便程序运行结束,这部分内存空间仍然不会被操作系统收回,从而成为被白白浪费掉的内存垃圾。这种现象也称为“内存泄露”。
2、atof()、atoi()、atol()
- : double atof(const char *str) //把参数 str 所指向的字符串转换为一个浮点数
- : int atoi(const char *str) //把参数 str 所指向的字符串转换为一个整数
- : long int atol(const char *str)// 把参数 str 所指向的字符串转换为一个长整数
- :
3、rand()、srand()
- : int rand(void)
- : void srand(unsigned int seed)
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- int main(){
- int i, n;
- time_t t;
- n = 5;
- /* 初始化随机数发生器 */
- srand((unsigned) time(&t));
- /* 输出 0 到 50 之间的 5 个随机数 */
- for( i = 0 ; i < n ; i++ ) {
- printf("%d\n", rand() % 50);
- }
- return(0);
- }
4、abort()、atexit()、exit()
4.1 void abort(void) // 使一个异常程序终止
switch(next_option){
case 'h':
print_usage(stdout , 0);
case '?':
print_usage(stderr , 1);
case -1:
break;
default:
abort();
}
4.2 int atexit(void (*func)(void)) // 当程序正常终止时,调用指定的函数 func,调用成功返回 0,否则返回一个非零值
4.3 void exit(int status) //使程序正常终止。
(1)exit(1)表示异常退出,在退出前可以给出一些提示信息,或在调试程序中察看出错原因。
(2)exit(0)表示正常退出。
5、getenv()
https://www.runoob.com/cprogramming/c-function-getenv.html
C 库函数 char *getenv(const char *name) 搜索 name 所指向的环境字符串,并返回相关的值给字符串。
- #include <stdio.h>
- #include <stdlib.h>
- int main ()
- {
- printf("PATH : %s\n", getenv("PATH"));
- printf("HOME : %s\n", getenv("HOME"));
- printf("ROOT : %s\n", getenv("ROOT"));
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- PATH : /sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin
- HOME : /
- ROOT : (null)
6、system()
- // int system(const char *string)
- #include <stdio.h>
- #include <string.h>
- #include<stdlib.h>
- int main (){
- char command[50];
- strcpy( command, "ls -l" );
- system(command);
- return(0);
- }
- drwxr-xr-x 2 apache apache 4096 Aug 22 07:25 hsperfdata_apache
- drwxr-xr-x 2 railo railo 4096 Aug 21 18:48 hsperfdata_railo
- rw------ 1 apache apache 8 Aug 21 18:48 mod_mono_dashboard_XXGLOBAL_1
- rw------ 1 apache apache 8 Aug 21 18:48 mod_mono_dashboard_asp_2
- srwx---- 1 apache apache 0 Aug 22 05:28 mod_mono_server_asp
- rw------ 1 apache apache 0 Aug 22 05:28 mod_mono_server_asp_1280495620
- srwx---- 1 apache apache 0 Aug 21 18:48 mod_mono_server_global
C 标准库 - <string.h>
https://www.runoob.com/cprogramming/c-standard-library-string-h.html
库变量
下面是头文件 string.h 中定义的变量类型:
size_t 这是无符号整数类型,它是 sizeof 关键字的结果。
下面是头文件 string.h 中定义的宏:
NULL 这个宏是一个空指针常量的值。
1、搜索,返回位置 “ * ”
*memchr(const void *str, int c, size_t n)
在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c(一个无符号字符)的位置。
- #include <stdio.h>
- #include <string.h>
- int main ()
- {
- const char str[] = "http://www.runoob.com";
- const char ch = '.';
- char *ret;
- ret = (char*)memchr(str, ch, strlen(str)); //这里返回 . 后面的一串字符,可用于截取字符
- printf("|%c| 之后的字符串是 - |%s|\n", ch, ret);
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- |.| 之后的字符串是 - |.runoob.com|
*strchr( str , c )
- char *strchr(const char *str,int c) //在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置,该函数返回在字符串 str 中第一次出现字符 c 的位置,如果未找到该字符则返回 NULL。结果是指向找到的 位置。
- #include <stdio.h>
- #include <string.h>
- int main (){
- const char str[] = "http://www.runoob.com";
- const char ch = '.';
- char *ret;
- ret = strchr(str, ch);
- printf("|%c| 之后的字符串是 - |%s|\n", ch, ret);
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- |.| 之后的字符串是 - |.runoob.com|
*strrchr(str , c)
在参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置
*strstr(const char *str1, const char *str2)
在字符串 str1中查找第一次出现字符串 str2 的位置,不包含终止符 '\0'
该函数返回在 haystack 中第一次出现 needle 字符串的位置,如果未找到则返回 null。
- #include <stdio.h>
- #include <string.h>
- int main(){
- const char haystack[20] = "RUNOOB";
- const char needle[10] = "NOOB";
- char *ret;
- ret = strstr(haystack, needle);
- printf("子字符串是: %s\n", ret);
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- 子字符串是: NOOB
2、比较,返回int
memcmp() 与 strncmp() 一毛一样
-
:int memcmp(const void *str1,const void *str2,size_t n) //把 str1 和 str2 的前 n 个字节进行比较
-
int strncmp(const char *str1, const char *str2, size_t n)
如果返回值 < 0,则表示 str1 小于 str2。
如果返回值 > 0,则表示 str1 大于 str2。
如果返回值 = 0,则表示 str1 等于 str2。
strcmp()
int strcmp(const char *str1, const char *str2)
返回值和 memcmp() 相同
strcoll()
int strcoll(const char *str1, const char *str2) //如果只比较字符串,和strcmp()一毛一样
函数说明:strcoll() 会依环境变量 LC_COLLATE 所指定的文字排列次序来比较 s1 和 s2 字符串。
默认情况下,LC_COLLATE 为"POSIX"或"C",strcoll() 和 strcmp() 一样根据ASCII比较字符串大小。
对于设置了 LC_COLLATE 语言环境的情况下,则根据 LC_COLLATE 设置的语言排序方式进行比较。例如,汉字会根据拼音进行比较。
3、复制,返回位置 “ * ”
*memcpy() 与 *memmove() 一毛一样
-
: void *memcpy(void *dest,const void *src,size_t n) //从 src 复制 n 个字符到 dest
-
: void *memmove(void *str1,const void *str2,size_t n)//
从 str2 复制 n 个字符到 str1,但是在重叠内存块这方面,memmove() 是比 memcpy() 更安全的方法。
如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后源区域的内容会被更改。
如果目标区域与源区域没有重叠,则和 memcpy() 函数功能相同。
str1 -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
str2 -- 指向要复制的数据源,类型强制转换为 void* 指针。
n -- 要被复制的字节数。
-
第一种用法
-
memcpy(dest, src, strlen(src)+1); // 将字符串复制到数组 dest 中
-
第二种用法
-
memcpy(d, s+11, 6);// 从第 11 个字符(r)开始复制,连续复制 6 个字符(runoob) // 或者 memcpy(d, s+11*sizeof(char), 6*sizeof(char));
*strcpy()
char *strcpy(char *dest, const char *src) //把 src 所指向的字符串复制到 dest。
需要注意的是如果目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况。
- #include <stdio.h>
- #include <string.h>
- int main()
- {
- char src[40];
- char dest[100];
- memset(dest, '\0', sizeof(dest));
- strcpy(src, "This is runoob.com");
- strcpy(dest, src);
- printf("最终的目标字符串: %s\n", dest);
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- 最终的目标字符串: This is runoob.com
*strncpy()
char *strncpy(char *dest, const char *src, size_t n)
把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。
4、memset()
复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。
char buf_ch[CLASSNAME_LENGTH] = {0};
memset(buf_ch, 0, CLASSNAME_LENGTH);//把 buf_ch[] 全部置 0.
5、strcat(str1 , str2) 、strncat(str1, str2, n)
把 src 所指向的字符串追加到 dest 所指向的字符串的结尾
- //char *strcat(char *dest, const char *src)
- //char *strncat(char *dest, const char *src, size_t n) // n -- 要追加的最大字符数
- #include <stdio.h>
- #include <string.h>
- int main () {
- char src[50], dest[50];
- strcpy(src, "This is source");
- strcpy(dest, "This is destination");
- strcat(dest, src); //连接两个字符串
- printf("最终的目标字符串: |%s|", dest);
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- 最终的目标字符串: |This is destinationThis is source|
6、strtok()
char *strtok(char *str, const char *delim) 分解字符串 str 为一组字符串,delim 为分隔符。
该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。
- #include <string.h>
- #include <stdio.h>
- int main () {
- char str[80] = "This is - www.runoob.com - website";
- const char s[2] = "-";
- char *token;
- /* 获取第一个子字符串 */
- token = strtok(str, s);
- /* 继续获取其他的子字符串 */
- while( token != NULL ) {
- printf( "%s\n", token );
- token = strtok(NULL, s); //这步有点特殊要注意
- }
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- This is
- www.runoob.com
- website
7、strlen(str)
size_t strlen(const char *str) 计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。测出的长度不是 str[50] 的50长,是str中具体有多少字符。
- #include <stdio.h>
- #include <string.h>
- int main ()
- {
- char str[50];
- int len;
- strcpy(str, "This is runoob.com");
- len = strlen(str);
- printf("|%s| 的长度是 |%d|\n", str, len);
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- |This is runoob.com| 的长度是 |18|
C 标准库 -<stdio.h>
打开关闭删除,重命名文件
fopen() 、fclose()
(1)C 库函数 FILE *fopen(const char *filename, const char *mode) 使用给定的模式 mode 打开 filename 所指向的文件。
filename -- 这是 C 字符串,包含了要打开的文件名称。
mode -- 这是 C 字符串,包含了文件访问模式,模式如下:
模式 | 描述 |
---|---|
"r" | 打开一个用于读取的文件。该文件必须存在。 |
"w" | 创建一个用于写入的空文件。如果文件名称与已存在的文件相同,则会删除已有文件的内容,文件被视为一个新的空文件。 |
"a" | 追加到一个文件。写操作向文件末尾追加数据。如果文件不存在,则创建文件。 |
"r+" | 打开一个用于更新的文件,可读取也可写入。该文件必须存在。 |
"w+" | 创建一个用于读写的空文件。 |
"a+" | 打开一个用于读取和追加的文件。 |
返回值
该函数返回一个 FILE 指针。否则返回 NULL,且设置全局变量 errno 来标识错误。
- fp = fopen("file.txt","r");
- if(fp == NULL) { //判断打开文件是否正常。
- perror("打开文件时发生错误");
- return(-1);
- }
- #include <stdio.h>
- int main(){
- FILE *fp;
- char c;
- fp = fopen("file.txt", "w");
- c = fgetc(fp);
- if( ferror(fp) ) { //测试给定流 stream 的错误标识符
- printf("读取文件:file.txt 时发生错误\n");
- }
- clearerr(fp); //清除给定流 stream 的文件结束和错误标识符
- if( ferror(fp) ) {
- printf("读取文件:file.txt 时发生错误\n");
- }
- fclose(fp);
- return(0);
- }
- 假设我们有一个文本文件 file.txt,它是一个空文件。让我们编译并运行上面的程序,因为我们试图读取一个以只写模式打开的文件,这将产生以下结果。
- 读取文件:file.txt 时发生错误
remove()
C 库函数 int remove(const char *filename) 删除给定的文件名 filename,以便它不再被访问。如果成功,则返回零。如果错误,则返回 -1,并设置 errno。
char filename[] = "file.txt";
ret = remove(filename);
if(ret == 0) {
printf("文件删除成功");
}
else {
printf("错误:不能删除该文件");
}
rename()
int rename(const char *old_filename, const char *new_filename) 把 old_filename 所指向的文件名改为 new_filename。如果成功,则返回零。如果错误,则返回 -1,并设置 errno。
char oldname[] = "file.txt";
char newname[] = "newfile.txt";
ret = rename(oldname, newname);
测定 stream 文件结束、错误标识
feof(FILE *stream)
速记:!feof(file) 没到结尾;feof(file) 到结尾
C 库函数 int feof(FILE *stream) 测试给定流 stream 的文件结束标识符。
参数stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
返回值当设置了与流关联的文件结束标识符时,检测到文件结束标识返回1,否则返回0。
int ferror(FILE *stream)
测试给定流 stream 的错误标识符。
clearerr()
- clearerr(fp); //清除给定流 stream 的文件结束和错误标识符
给定流 stream 读写文件
(写入到流 stream)fwrite()
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 把 ptr 所指向的数组中的数据写入到给定流 stream 中。
- #include<stdio.h>
- int main (){
- FILE *fp;
- char str[] = "This is runoob.com";
- fp = fopen( "file.txt" , "w" );
- fwrite(str, sizeof(str) , 1, fp ); //fwrite(str, strlen(str) + 1, 1, fp);
- fclose(fp);
- return(0);
- }
- 让我们编译并运行上面的程序,这将创建一个文件 file.txt,它的内容如下:
- This is runoob.com
(写入到流 stream)fprintf()
int fprintf(FILE *stream, const char *format, ...) 发送格式化输出到流 stream 中。
参数stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
format -- 这是 C 字符串,包含了要被写入到流 stream 中的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。
-
#include <stdio.h>
-
#include <stdlib.h>
-
int main(){
-
FILE * fp;
-
fp = fopen ("file.txt", "w+");
-
fprintf(fp, "%s %s %s %d", "We", "are", "in", 2014);
-
fclose(fp);
-
return(0);
-
}
-
让我们编译并运行上面的程序,这将创建文件 file.txt,它的内容如下:
-
We are in 2014
与区别printf sprintf ,输出到的位置不同
int printf(const char *format, ...)
发送格式化输出到标准输出 stdout。int sprintf(char *str, const char *format, ...)
发送格式化输出到字符串。printf sprintf fprintf
vprintf vsprintf vfprintf
(写入到流 stream)vfprintf()
int vfprintf(FILE *stream, const char *format, va_list arg) 使用参数列表发送格式化输出到流 stream 中。
-
#include <stdio.h>
-
#include <stdarg.h>
-
void WriteFormatted (FILE * stream, const char * format, ...) {
-
va_list args;
-
va_start (args, format);
-
vfprintf (stream, format, args);
-
va_end (args);
-
}
-
int main ()
-
{
-
FILE * pFile;
-
pFile = fopen ("myfile.txt","w");
-
WriteFormatted (pFile,"Call with %d variable argument.\n",1);
-
WriteFormatted (pFile,"Call with %d variable %s.\n",2,"arguments");
-
fclose (pFile);
-
return 0;
-
}
与区别vprintf vsprintf
int vprintf(const char *format, va_list arg)
使用参数列表发送格式化输出到标准输出 stdout。int vsprintf(char *str, const char *format, va_list arg)
使用参数列表发送格式化输出到字符串。printf sprintf fprintf
vprintf vsprintf vfprintf
(写入到流 stream) fputc() 与 putc() 一毛一样
int fputc(int char, FILE *stream) 把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。
如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。
- #include <stdio.h>
- int main () {
- FILE *fp;
- int ch;
- fp = fopen("file.txt", "w+");
- for( ch = 33 ; ch <= 100; ch++ ) {
- fputc(ch, fp); //虽然是int ,但是会转换成字符进行输入
- }
- fclose(fp);
- return(0);
- }
- 让我们编译并运行上面的程序,这将在当前目录中创建文件 file.txt,它的内容如下:
- !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcd
(写入到流 stream) fputs()
int fputs(const char *str, FILE *stream) 把字符串写入到指定的流 stream 中,但不包括空字符 ‘\0’。该函数返回一个非负值,如果发生错误则返回 EOF。
- #include <stdio.h>
- int main (){
- FILE *fp;
- fp = fopen("file.txt", "w+");
- fputs("这是 C 语言。", fp);
- fputs("这是一种系统程序设计语言。", fp);
- fputs("这是 C 语言。: \0 dsgf ", fp); // \0 就是空字符
- fclose(fp);
- return(0);
- }
- 让我们编译并运行上面的程序,这将创建文件 file.txt,它的内容如下:
- 这是 C 语言。这是一种系统程序设计语言。
(读取流 stream)fread()
size_t fread(void *ptr, size_t size, size_t count, FILE *stream) 从给定流 stream 读取数据到 ptr 所指向的数组中。
size 是每次读取的字节数
count 是读取次数
-
例如 从文件fp里读取100个字节 可用以下语句
-
fread(buffer,100,1,fp)
-
fread(buffer,50,2,fp)
-
fread(buffer,1,100,fp)
成功读取的元素总数会以 size_t 对象返回,size_t 对象是一个整型数据类型。如果总数与 nmemb 参数不同,则可能发生了一个错误或者到达了文件末尾。
(读取流 stream) fscanf()
int fscanf(FILE *stream, const char *format, ...) 从流 stream 读取格式化输入
- #include <stdio.h>
- #include <stdlib.h>
- int main(){
- char str1[10], str2[10], str3[10];
- int year;
- FILE * fp;
- fp = fopen ("file.txt", "w+");
- fputs("We are in 2014", fp);
- rewind(fp);
- fscanf(fp, "%s %s %s %d", str1, str2, str3, &year);
- printf("Read String1 |%s|\n", str1 );
- printf("Read String2 |%s|\n", str2 );
- printf("Read String3 |%s|\n", str3 );
- printf("Read Integer |%d|\n", year );
- fclose(fp);
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- Read String1 |We|
- Read String2 |are|
- Read String3 |in|
- Read Integer |2014|
(读取流 stream)fgetc()
int fgetc(FILE *stream) 从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。
该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。
- #include <stdio.h>
- int main (){
- FILE *fp;
- int c;
- int n = 0;
- fp = fopen("file.txt","r");
- if(fp == NULL) {
- perror("打开文件时发生错误");
- return(-1);
- }
- do {
- c = fgetc(fp);
- if( feof(fp) ){ //速记:!feof(file) 没到结尾;feof(file) 到结尾
- break ;
- }
- printf("%c", c);
- }while(1);
- fclose(fp);
- return(0);
- }
- 假设我们有一个文本文件 file.txt,它的内容如下。文件将作为实例中的输入:
- We are in 2014
- 让我们编译并运行上面的程序,这将产生以下结果:
- We are in 2014
(读取流 stream)*fgets
char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
-
n -- 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。
如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。如果发生错误,返回一个空指针。
- #include <stdio.h>
- int main(){
- FILE *fp;
- char str[60];
- /* 打开用于读取的文件 */
- fp = fopen("file.txt" , "r");
- if(fp == NULL) {
- perror("打开文件时发生错误");
- return(-1);
- }
- if( fgets (str, 60, fp)!=NULL ) {
- /* 向标准输出 stdout 写入内容 */
- puts(str);
- }
- fclose(fp);
- return(0);
- }
- 假设我们有一个文本文件 file.txt,它的内容如下。文件将作为实例中的输入:
- We are in 2014
- 让我们编译并运行上面的程序,这将产生以下结果:
- We are in 2014
(读取流 stream)ungetc()
int ungetc(int char, FILE *stream) 把字符 char(一个无符号字符)推入到指定的流 stream 中,以便它是下一个被读取到的字符。
- #include <stdio.h>
- int main (){
- FILE *fp;
- int c;
- char buffer [256];
- fp = fopen("file.txt", "r");//这里是read,若用fputc ,需要用 ‘r+’,一边读一边写
- if( fp == NULL ){
- perror("打开文件时发生错误");
- return(-1);
- }
- while(!feof(fp)) {
- c = getc (fp);
- /* 把 ! 替换为 + */
- if( c == '!' ){
- ungetc ('+', fp); //决不可换成 putc(),fputc能改变文件,ungetc不改变源文件。
- }
- else {
- ungetc(c, fp);
- }
- fgets(buffer, 255, fp);
- fputs(buffer, stdout);
- }
- return(0);
- }
- 假设我们有一个文本文件 file.txt,它的内容如下。文件将作为实例中的输入:
- this is runoob
- !c standard library
- !library functions and macros
- 让我们编译并运行上面的程序,这将产生以下结果:
- this is runoob
- +c standard library
- +library functions and macros
输出到字符串
(输出到字符串) sprintf()
int sprintf(char *str, const char *format, ...) 发送格式化输出到 str 所指向的字符串。
-
#include <stdio.h>
-
#include <math.h>
-
int main()
-
{
-
char str[80];
-
sprintf(str, "Pi 的值 = %f", M_PI);
-
puts(str);
-
return(0);
-
}
-
让我们编译并运行上面的程序,这将产生以下结果:
-
Pi 的值 = 3.141593
sprintf() 和 snprintf() 的区别在于 snprintf() 多了一个size参数,可控制要写入的字符的最大数目
(输出到字符串) snprintf(char *str, size_t size, const char *format, ...)
C 库函数 int snprintf(char *str, size_t size, const char *format, ...) 设将可变参数(...)按照 format 格式化成字符串,并将字符串复制到 str 中,size 为要写入的字符的最大数目,超过 size 会被截断。
下面是 snprintf() 函数的声明。
int snprintf ( char * str, size_t size, const char * format, ... );
char buf_ch[CLASSNAME_LENGTH] = {0};
snprintf(array[i], CLASSNAME_LENGTH, "%s", buf_ch);//格式化buf_ch为字符串,并复制到array[i]中。(buf_ch中正好有CLASSNAME_LENGTH个字符)
参数
str -- 目标字符串。
size -- 拷贝字节数(Bytes)。
format -- 格式化成字符串。
... -- 可变参数。
返回值
(1) 如果格式化后的字符串长度小于等于 size,则会把字符串全部复制到 str 中,并给其后添加一个字符串结束符 \0;如果格式化后的字符串长度大于 size,超过 size 的部分会被截断,只将其中的 (size-1) 个字符复制到 str 中,并给其后添加一个字符串结束符 \0。
(2) int j = snprintf(buffer, 6, "%s\n", s);返回值为欲写入的字符串 s的长度,与参数size 没关系。
(输出到字符串) vsprintf()
int vsprintf(char *str, const char *format, va_list arg) 使用参数列表发送格式化输出到字符串。
- #include <stdio.h>
- #include <stdarg.h>
- char buffer[80];
- int vspfunc(char *format, ...){
- va_list aptr;
- int ret;
- va_start(aptr, format);
- ret = vsprintf(buffer, format, aptr);
- va_end(aptr);
- return(ret);
- }
- int main(){
- int i = 5;
- float f = 27.0;
- char str[50] = "runoob.com";
- vspfunc("%d %f %s", i, f, str);
- printf("%s\n", buffer);
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- 5 27.000000 runoob.com
(从字符串读取) sscanf()
int sscanf(const char *str, const char *format, ...) 从字符串读取,格式化输入到给定的字符串数组中。
如果成功,该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回 EOF。
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- int main() {
- int day, year;
- char weekday[20], month[20], dtm[100];
- strcpy( dtm, "Saturday March 25 1989" );
- sscanf( dtm, "%s %s %d %d", weekday, month, &day, &year );//如果是int 加&
- printf("%s %d, %d = %s\n", month, day, year, weekday );
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- March 25, 1989 = Saturday
标准输出 输入
(stdout) printf
printf("ASCII 值 = %d, 字符 = %c\n", ch , ch );
(stdout)vprintf
int vprintf(const char *format, va_list arg) 使用参数列表发送格式化输出到标准输出 stdout。
- #include <stdio.h>
- #include <stdarg.h>
- void WriteFrmtd(char *format, ...) {
- va_list args;
- va_start(args, format);
- vprintf(format, args);
- va_end(args);
- }
- int main () {
- WriteFrmtd("%d variable argument\n", 1);
- WriteFrmtd("%d variable %s\n", 2, "arguments");
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- 1 variable argument
- 2 variable arguments
(stdout)putchar()
getchar() 和 getc()用法相同,
但putchar()和 putc()用法不同。putchar(ch);//putc(ch, stdout); 这样的效果相等。
fputc() 与 putc() 一毛一样
int putchar(int char) 把参数 char 指定的字符(一个无符号字符)写入到标准输出 stdout 中。
该函数以无符号 char 强制转换为 int 的形式返回写入的字符,如果发生错误则返回 EOF。
- #include <stdio.h>
- int main ()
- {
- char ch;
- for(ch = 'A' ; ch <= 'Z' ; ch++) {
- putchar(ch); //putc(ch, stdout); 这样的效果相等
- }
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- ABCDEFGHIJKLMNOPQRSTUVWXYZ
(stdout)puts()
int puts(const char *str) 把一个字符串写入到标准输出 stdout,直到空字符,但不包括空字符。换行符会被追加到输出中。
如果成功,该函数返回一个非负值为字符串长度(包括末尾的 \0),如果发生错误则返回 EOF。
- #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);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- RUNOOB1
- RUNOOB2
(stdin) scanf()
int scanf(const char *format, ...) 从标准输入 stdin 读取格式化输入。
如果成功,该函数返回成功匹配和赋值的个数。如果到达文件末尾或发生读错误,则返回 EOF。
-
#include<stdio.h>
-
int main(void)
-
{
-
int a,b,c;
-
printf("请输入三个数字:");
-
scanf("%d%d%d",&a,&b,&c);
-
printf("%d,%d,%d\n",a,b,c);
-
return 0;
-
}
使用一个scanf函数提供的“%[]”格式来输入,这个格式可以让我们进行多字符的输入,同时决定输入结束的字符,只需要使用 ”%[^+我们需要停止的字符]” 下面为大家实际操作一波:
scanf("%[^\n]", str);
(stdin) getchar() 与 getc()
getchar() 和 getc()都可用于接收 stdin ,参数不一样,
但putchar()和 putc()用法不同。putchar(ch);//putc(ch, stdout); 这样的效果相等。
fputc() 与 putc() 一毛一样
int getchar(void) 从标准输入 stdin 获取一个字符(一个无符号字符)。这等同于 getc 带有 stdin 作为参数。
int getc(FILE *stream) 从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。
- #include <stdio.h>
- int main (){
- char c;
- printf("请输入字符:");
- c = getchar();
- printf("输入的字符:");
- putchar(c);
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- 请输入字符:a
- 输入的字符:a
- char c;
- printf("请输入字符:");
- c = getc(stdin);
- printf("输入的字符:");
- putc(c, stdout);
(stdin) *gets()
char *gets(char *str) 从标准输入 stdin 读取一行,并把它存储在 str 所指向的字符串中。当读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
如果成功,该函数返回 str。如果发生错误或者到达文件末尾时还未读取任何字符,则返回 NULL。
- #include <stdio.h>
- int main(){
- char str[50];
- printf("请输入一个字符串:");
- gets(str);
- printf("您输入的字符串是:%s", str);
- return(0);
- }
- 让我们编译并运行上面的程序,这将产生以下结果:
- 请输入一个字符串:runoob
- 您输入的字符串是:runoob
tt
int fflush(FILE *stream)
刷新流 stream 的输出缓冲区。
int fgetpos(FILE *stream, fpos_t *pos)
获取流 stream 的当前文件位置,并把它写入到 pos。
FILE *freopen(const char *filename, const char *mode, FILE *stream)
把一个新的文件名 filename 与给定的打开的流 stream 关联,同时关闭流中的旧文件。
int fseek(FILE *stream, long int offset, int whence)
设置流 stream 的文件位置为给定的偏移 offset,参数 offset 意味着从给定的 whence 位置查找的字节数。
void perror(const char *str)
把一个描述性错误消息输出到标准错误 stderr。首先输出字符串 str,后跟一个冒号,然后是一个空格。
C标准库-<ctype.h>
()、isalpha() 判断一个字符是否是字母
#include<ctype.h>