int main (int argc, char * argv[]) argc 是命令行总的参数个数,记录了用户在运行程序的命令行中输入的参数的个数; argv[] 存放了命令行输入的全部字符
int main (int argc, char * argv[])
argc 是命令行总的参数个数,记录了用户在运行程序的命令行中输入的参数的个数;
argv[] 存放了命令行输入的全部字符串,包含 argc 个参数,其中第 0 个参数是程序的全名,至少有一个字符指针,指向程序中可执行文件的文件名,有些版本的编译器中还包括程序文件所在的路径;
程序中得到这些参数的工作是编译器完成的,编译器将输入参数的信息放入 main 函数的参数列表中,赋值过程也是编译器完成的。
stat.h
导入 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 filesnlink_t st_nlink; //符号链接数uid_t st_uid; //用户IDgid_t st_gid; //组IDoff_t st_size; //size in bytes,for regular filestime_t st_st_atime; //最后一次访问的时间time_t st_mtime; //文件内容最后一次被更改的时间time_t st_ctime; //文件结构最后一次被更改的时间blksize_t st_blksize; //best I/O block sizeblkcnt_t st_blocks; //number of disk blocks allocated};
文件类型包括了:普通文件、目录文件、块特殊文件、字符特殊文件、套接字、FIFO、符号链接,文件类型信息包含在 stat 结构的 st_mode 成员中,可以通过宏确定文件类型,这些宏是 stat 结构中的 st_mode 成员:S_ISREG()、S_ISDIR()、S_ISCHR()、S_ISBLK()、S_ISFIFO()、S_ISSOCK()
S_TYPEISMQ() 表示消息队列、S_TYPEISSEM() 表示信号量、S_TYPEISSHM() 表示共享存储对象。
进程每次打开,创建或删除一个文件时,内核就进行文件访问权限测试,测试可能涉及文件所有者(st_uid 和 st_gid),进行的有效 ID 以及进程的附加组 ID:
(1).若进程的有效用户ID是0(超级用户),则允许访问。
(2).若进程的有效用户ID等于文件的有效用户ID,那么若所在者适当的访问权限被设置,则允许访问。
(3).若进程的有效组ID或进程的附加组ID之一等于文件的组ID,那么组适当的访问权限位被设置,则允许访问。
(4).若其他用户适当的访问权限位被设置,则允许访问。
按顺序执行以上四步。
stat()、lstat()、fstat()
stat()、lstat()、fstat() 函数都是获取文件(普通文件、目录、管道、socket、字符、块)的属性。
int stat(const char *restrict pathname, struct stat *restrict buf); 提供文件名字,获取文件对应属性;
int fstat(int filedes, struct stat *buf); 通过文件描述符,获取文件对应的属性;
int lstat(const char *restrict pathname, struct stat *restrict buf); 连接文件描述符,获取文件属性
fstat() 用来将参数 filedes 所指向的文件状态复制到参数 buf 所指向的结构中(structstat),fstat() 与 stat() 作用完全相同,不同之处在于传入的参数为已打开的文件描述符
返回值:执行成功返回 0,失败返回 -1,错误代码保存在 errno;
#include <stdio.h>#include <stdlib.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>main(){ struct stat buf; int fd; fd = open("/etc/passwd", O_RDONLY); fstat(fd, &buf); fstat(fd, &buf); printf("/etc/passwd file size = %d/n", (int)(buf.st_size));}
malloc()、calloc()、realloc()、free()、memcpy()
头文件 malloc.h(alloc.h 两个头文件内容相同的)
函数声明:extern void *malloc(unsigned int num_bytes);
分配长度为 num_bytes 字节的内存块,分配成功返回指向被分配内存的指针,否则返回空指针 NULL。
#include <stdio.h>#include <malloc.h>int main(){ char *p; p = (char *)malloc(100); if(p) printf("Memory Allocated at %x/n", p); else printf("Not Enough Memory!/n"); free(p); return 0;}
malloc 向系统申请分配指定 size 个字节的内存空间,返回类型是 void* 类型(未确定类型的指针,C、C++规定,void *类型可以强制转化为任何其它类型的指针)
当内存不再使用时,应使用 free() 函数将内存块释放;
void free(void *ptr); //#include <stdlib.h> 或 #include <malloc.h>
释放 ptr 指向的存储空间,被释放的空间通常被送入可用存储区池,以后可在调用 malloc、realloc 以及 realloc 函数再分配(连续两次 free 会报错,malloc 次数要和 free 此时相对)
free(str) 后指针仍然指向原来的堆地址,即你仍然可以继续使用,但很危险,因为操作系统已经认为这块内存可以使用,会分配给其它程序,这种情况就叫“野指针”(指程序员或操作者不能控制的指针,不是 NULL 指针,而是指向“垃圾”的指针),最好 free() 了以后再置空,str = NULL,即放弃使用它;
calloc() 函数用来动态地分配内存空间并初始化为 0:
void * calloc(size_t num, size_t size);
calloc() 在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为 0,所以它的结构是分配了 num*size 个字节长度的内存空间,并且每个字节的值都是 0。
分配成功返回指向该内存的地址,失败则返回 NULL。
realloc() 函数用来更改已经配置的内存空间,即更改由 malloc() 函数分配的内存空间大小,如果将分配的内存减少,realloc 仅仅是改变索引的信息;
realloc(void * __ptr, size_t __size)
如果是将内存扩大:
1)如果当前内存段后面有需要的内存空间,则直接扩展这段内存空间,realloc() 将返回原指针;
2)如果当前内存段后面的空闲字节不够,那么就使用堆中第一个能满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据块释放掉,返回新的内存块位置。
3)如果申请失败,将返回 NULL,此时,原来的指针仍然有效;
如果调用成功,不管当前内存段后面的空闲空间是否满足要求,都会释放原来的指针,重新返回一个指针,虽然返回的指针有可能和原来的指针一样,即不能再次释放掉原来的指针。(如果当前内存段后有足够的空间,则返回原来的指针,如果没有足够的空间,会返回一个新的内存段指针)
#include <string.h>
void * memcpy(void *destin, const void *src, size_t n);
有 src 指向地址为起始地址的连续 n 个字节的数据复制到以 destin 指向地址为起始地址的空间内,返回一个指向 dest 的指针。
source 和 destin 所指内存区域不能重置,函数返回指向 distin 的指针;
errno.h
C 语言错误处理,提供了宏 errno、 perror() 函数和 strerrno() 函数
perror() 函数显示的字符串传递,然后接一个冒号,一个空格,然后目前 errno 值得文字表述;
strerrno() 函数返回一个指针,指向目前的 errno 值的文字描述。
errno 在头文件 errno.h 中定义
#ifndef errnoextern int errno;#endif#define EDOM 33 /* Math argument out of domain of function */
errno 常见用法是在调用库函数之前清零,随后再进行检查。
二级指针
看代码的过程中,很多地方遇到了类似这样的声明 void ** A = &B,A(即 B 的地址)是指向指针的指针,称为二级指针,用于存放二级指针的变量称为二级指针变量,根据 B 的情况不同,二级指针又分为指向指针变量的指针和指向数组的指针。
任何值都有地址,一级指针的值虽然是地址,但这个地址做为一个值亦需要空间来存放,是空间就具有地址,这就是存放地址这一值的空间所具有的地址,二级指针就是为了获取这个地址。
数组也是一种指针,指针+1 的操作类似于数组下标加一,指针加一实际上是相对于声明指针时类型而言的,如果声明指针时为 int 类型,那么指针加一,实际上移动了 4 个字符位。
在 C 和 C++ 中,void 代表一种抽象的无类型,任何变量都应该是有类型的,void * 即为无类型指针,void * 可以指向任何类型的数据,因为 void * 的声明指针类型可以转变成任何其它类型。
内存管理函数 | 内存控制函数
函数 | 说明 |
getpagesize() | 取得内存页大小 |
mmap() | 建立内存映射 |
munmap() | 接触内存映射 |
memccpy() | 复制内存中的内容 |
memchr() | 在内存中查找特定字符 |
memcmp() | 比较内存前 n 个字节 |
附带 C 语言函数手册:http://c.biancheng.net/cpp/u/hs3/