int小于等于数据线宽度,size_t大于等于地址线宽度。
数组和指针
char *c = "abc"//类似于常量,不能更改,会出错
char c[] = "abc" //c[]就是普通的字符串数组,可以更改,不会出错
————————————————————————————————————————————————————
结构体和指针
使用动态内存分配的方式创建结构体,可以防止栈空间不足的情况。
#include <stdio.h>
struct strudent //创建一个结构体
{
char *name;
char age;
};
int main(void)
{
int i;
struct strudent *st=malloc(sizeof(struct strudent)*3); //创建连续三个strudent结构体大小的空间
struct strudent *temp=st; //将temp指向st,保存st的原始地址,用于free等,原因:st的地址在后期会发生改变
st->name = malloc(sizeof(char)*20); //创建name的空间,20字节
st->name = "zhangsan";
st->age = 21;
st++; //类似于下一个数组
st->name = "lisi";
st->age = 20;
st++;
st->name = "wangwu";
st->age = 20;
st = temp; //初始化st的地址
for(i=0; i<3; i++) //打印三个人的信息
{
printf("name: %s\tage: %d\n", st->name, st->age);
st++;
}
free(st->name); //释放name的空间,一定要先释放结构体里面的空间
free(temp); //释放st的空间,这是要最后释放的
return 0;
}
运行结果:
————————————————————————————————————————————————————
typedef和define
可参考: http://blog.sina.com.cn/s/blog_5a2bbc860101c9ny.html
typedef定义结构体
typydef struct
{
int a;
}abc;
int main(void)
{
abc a; //不用typedef的话,需要这样写: struct abc a;
//define无法找到这一点
return 0;
}
typedef定义数据类型
typedef unsigned char BYTE
typedef定义宏常量
这里写代码片
typedef定义函数指针
首先,看下面的代码
#include <stdio.h>
#include <string.h>
//将两个字符串合并在一起
char *mystrcat(char *s1, char *s2)
{
strcat(s1, s2);
return s1;
}
//char *(*p)(char *, char *) 为 char *mystrcat(char *s1, char *s2)的函数指针
char *test(char *(*p)(char *, char *), char *s1, char *s2)
{
return p(s1, s2);
}
int main(void)
{
char s1[100] = "hello";
char s2[100] = "world";
char *s = test(mystrcat, s1, s2);
printf("%s\n", s);
return 0;
}
typedef char *(*STRCAT)(char *, char *); //使用STRCAT替换p的位置
//STRCAT 等于 char *(*p)(char *, char *)
char *test(STRCAT p, char *s1, char *s2)
{
return p(s1, s2);
}
运行结果同上
char *(*p[10])(char *s1, char *s2); //创建十个指针函数,char *(*p)(char *s1, char *s2)
STRCAT p[10]; //同上,便于观看
返回值是一个指向char * ( * p)(char , char )数据类型的指针
#include <stdio.h>
#include <string.h>
typedef char *(*STRCAT)(char *, char *);
char *mystrcat(char *s1, char *s2)
{
strcat(s1, s2);
return s1;
}
STRCAT get_mystrcat()
{
return mystrcat;
}
int main(void)
{
STRCAT p;
p=get_mystrcat();
char s1[100] = "hello";
char s2[100] = "world";
p(s1, s2);
printf("%s\n", s1);
return 0;
}
运行结果同上
文件操作
文件使用方式
文件使用方式 | 含义 | 如果指定的文件不存在 |
---|---|---|
“r”(只读) | 为了输入数据,打开一个已存在的文本文件 | 出错 |
“w”(只写) | 为了输出数据,打开一个文本文件 | 建立新文件 |
“a”(追加) | 向文本文件尾添加数据 | 建立新文件 |
“rb”(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb”(只写) | 为了输出数据,打开一个二进制文件 | 建立新文件 |
“ab”(追加) | 向二进制文件尾添加数据 | 建立新文件 |
“r+”(读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+”(读写) | 为了读和写,建立一个新的文本文件 | 建立新文件 |
“a+”(读写) | 为了读和写,向文本文件尾添加数据 | 建立新文件 |
“rb+”(读写) | 为了读和写,打开一个二进制文件 | 出错 |
“wb+”(读写) | 为了读和写,建立一个新的二进制文件 | 建立新文件 |
“ab+”(读写) | 为了读和写,向二进制文件尾添加数据 | 建立新文件 |
可参考: http://www.cnblogs.com/kangjianwei101/p/5220021.html
二进制和文本模式的区别
1.在Windows系统中,文本模式下,文件以"\r\n"代表换行.若以文本模式打开文件,并用fputs等函数写入换行符"\n"时,函数会自动在"\n"前面加上"\r".即实际写入文件的是"\r\n".
2.在类Unix/Linux系统中文本模式下,文件以"\n"代表换行.所以Linux系统中在文本模式和二进制模式下并无区别.
EOF与feof
EOF代表文件结尾,是个常量.
feof判断文件是否到结尾了,函数返回true,说用已到结尾,使用方法:feof(*fp);
相关函数
函数名 | 函数定义 | 返回值 | 用途 |
---|---|---|---|
fopen | FILE *fopen(char *pname, char *mode) | 正常:被打开文件的文件指针, 异常:NULL,打开失败 | 打开文件 |
fclose | int fclose(FILE *fp) | 正常:0, 异常:EOF,关闭失败 | 关闭文件 |
fgetc | int fgetc(FILE *fp) | 正常:读取字符, 异常:EOF | 读取一个字符 |
fputc | int fputc(int ch, FILE *fp) | 正常: 要写入的字符, 异常: EOF | 写入一个字符 |
fgets | char *fgets(char *str, int n, FILE *fp) | 正常: 字符串内存首地址, 异常: NULL | 读取一个字符串 |
fputs |
二进制文件拷贝
可以对任意文件进行拷贝
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
FILE *sp = fopen("D:\\temp\\a.txt", "rb"); //源文件
FILE *dp = fopen("D:\\temp\\b.txt", "wb"); //目标文件
char buf[1024 * 4]; //操作系统最小内存页为4k
while(!feof(sp))
{
memset(buf, 0, sizeof(buf));
size_t res = fread(buf, sizeof(char), sizeof(buf), sp); //返回从源文件中读取的字节数
fwrite(buf, sizeof(char), res, dp); //从源文件中读取多少字节,就往目标文件中写入多少字节
}
fclose(sp);
fclose(dp);
printf("end\n"); //表示拷贝结束
return 0;
}
二进制文件加密
可以对任意文件进行加密
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void code(char *p, size_t n) //加密,加3
{
size_t i;
for(i = 0; i < n; i++)
{
p[i] += 3;
}
}
void decode(char *p, size_t n) //解密.减3
{
size_t i;
for(i = 0; i < n; i++)
{
p[i] -= 3;
}
}
int main(void)
{
FILE *sp = fopen("D:\\temp\\a.txt", "rb"); //源文件
FILE *dp = fopen("D:\\temp\\b.txt", "wb"); //目标文件
char buf[1024 * 4]; //操作系统最小内存页为4k
while(!feof(sp))
{
memset(buf, 0, sizeof(buf));
size_t res = fread(buf, sizeof(char), sizeof(buf), sp); //返回从源文件中读取的字节数
code(buf, res); //加密,解密时将code换成decode
fwrite(buf, sizeof(char), res, dp); //从源文件中读取多少字节,就往目标文件中写入多少字节
}
fclose(sp);
fclose(dp);
printf("end\n"); //表示拷贝结束
return 0;
}
结构体与二进制文件
#include <sys/stat.h>
//stat函数可以返回一个结构,里面包括文件的全部属性
struct stat
{
mode_t st_mode; //文件类型和权限信息
ino_t st_ino; //i结点标识
dev_t st_dev; //device number (file system)
dev_t st_rdev; //device number for special files
nlink_t st_nlink; //符号链接数
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
off_t st_size; //size in bytes,for regular files
time_t st_st_atime; //最后一次访问的时间
time_t st_mtime; //文件内容最后一次被更改的时间
time_t st_ctime; //文件结构最后一次被更改的时间
blksize_t st_blksize; //best I/O block size
blkcnt_t st_blocks; //number of disk blocks allocated
};
动态分配内存拷贝文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
int main(void)
{
clock_t c1 = clock(); //得到系统当前时间,单位:ms
struct stat st = { 0 }; //定义一个结构体,名字叫st
stat("D:\\temp\\a.txt", &st); //调用完stat函数之后,文件相关的信息就保存在了st结构中
//st.st_size得到文件的大小
char *array = malloc(st.size); //根据文件的大小在堆中动态的分配一块内存
FILE *p = fopen("D:\\temp\\a.txt", "rb");
fread(array, sizeof(char), st.st_size, p); //相当于一下把整个文件放入了内存
fclose(p);
p = fopen("D:\\temp\\a.txt", "wb");
fwrite(array, sizeof(char), st.st_size, p); //将堆中的信息一下都写入文件
fclose(p);
clock_t c2 = clock(); //得到系统当前时间,单位:ms
printf("end, %ums\n", c2-c1);
return 0;
}
fseek与ftell
fseek函数
函数名:fseek函数
头文件:#include “stdio.h”
功能:把与fp有关的文件位置指针放到一个指定位置。
格式: int fseek(FILE *stream, long offset, int fromwhere);
起始位置 | 代表文件位置 |
---|---|
SEEK_SET | 文件开头 |
SEEK_CUR | 文件当前位置 |
SEEK_END | 文件末尾 |
说明:
offset:偏移量
fromwhere:起始位置
其中,"位移量"是long型数据,它表示位置指针相对于"起始点"移动的字节数。
如果位移量是一个正数,表示从"起始点"开始往文件尾方向移动;
如果位移量是一个负数,则表示从"起始点"开始往文件头方向移动。
"起始点"不能任意设定,它只能是在stdio.h中定义的三个符号常量之一:
注意:fseek函数的文件指针,应该为已经打开的文件。如果没有打开的文件,那么将会出现错误。
ftell函数
函数名:ftell函数
头文件:#include “stdio.h”
功能:得到流式文件的当前读写位置,其返回值是当前读写位置偏离文件头部的字节数。
格式: long ftell(FILE *fp);
fflush函数
函数名:fflush函数
头文件:#include “stdio.h”
功能:清空文件缓冲区,将数据保存在磁盘中。
格式: int fflush(FILE* stream);
返回值:成功返回0,失败返回EOF。
说明:fflush()也可用于标准输入(stdin)和标准输出(stdout),用来清空标准输入输出缓冲区。
remove与rename
remove函数
函数名:remove函数
头文件:#include “stdio.h”
功能:filename为要删除的文件名,可以为一目录。如果参数filename 为一文件,则调用unlink()处理;若参数filename 为一目录,则调用rmdir()来处理。
格式: int remove(char * filename);
返回值:成功则返回0,失败则返回-1,错误原因存于errno。
错误代码 | 原因 |
---|---|
EROFS | 欲写入的文件为只读文件。 |
EFAULT | 参数filename 指针超出可存取内存空间。 |
ENAMETOOLONG | 参数filename 太长。 |
ENOMEM | 核心内存不足。 |
ELOOP | 参数filename 有过多符号连接问题。 |
EIO | I/O 存取错误。 |
rename函数
函数名:rename函数
头文件:#include “stdio.h”
功能:更改文件名,oldname为旧文件名,newname为新文件名。
格式: int rename(char * oldname, char * newname);
返回值:修改文件名成功则返回0,否则返回-1。
重命名文件:
- 如果newname指定的文件存在,则会被删除。
- 如果newname与oldname不在一个目录下,则相当于移动文件。
重命名目录:
- 如果oldname和oldname都为目录,则重命名目录。
- 如果newname指定的目录存在且为空目录,则先将newname删除。
- 对于newname和oldname两个目录,调用进程必须有写权限。
- 重命名目录时,newname不能包含oldname作为其路径前缀。例如,不能将/usr更名为/usr/foo/testdir,因为老名字( /usr/foo)是新名字的路径前缀,因而不能将其删除。
————————————————————————————————————————————————————
const 用法
int main(void)
{
//以下变量需要初始化,不然出错
const int a;
int const b; //和上一个一样
const int *c; //const修饰的是指针所指向的内存空间,不能被修改
int * const d; //指针变量的值不能被修改
const int * const e; //指针变量的值不能被修改,所指向的空间的值也不能被修改
return 0;
}
————————————————————————————————————————————————————
此文章作为笔者学习笔记,记入经常要用,但会忘记的函数和使用方法。笔者拿出来和大家分享,出现雷同,属于正常。
日后更新,永不放弃, ̄□ ̄||
人生最重要的,不是得到了什么,而是经历了什么。
当前所有的苦难,都会在不久的未来发挥它应有的价值。 ——ZZ