分配数组
int *x, *y;
x = malloc(50*sizeof(int));
if(!x) {
perror("malloc");
return 1;
}
y = calloc(50, sizeof(int));
if (!y) {
perror("calloc");
return 1;
}
calloc会将所申请的内存全部填充0,malloc则不会。
调整内存分配的大小
#include <stdlib.h>
void* realloc(void* ptr, size_t size);
创建匿名内存映射
#include <sys/mman.h>
void * mmap(void* start, size_t length, int port, int flags, int fd, off_t offset);
int munmap(void* start, size_t length);
void* p;
p = mmap(NULL, // 此处无关紧要
512*1024, // 512KB
PROT_READ | PROT_WRITE, // 可供读取和写入
MAP_ANONYMOUS | MAP_PRIVATE, // 匿名与私有
-1, // fd 忽略
0); // offset 忽略
if (p == MAP_FAILED)
perror("mmap")
else
-- 第一个参数start设定为NULL,表示匿名映射的起始地址由内核自行决定,也可以指定非NULL的值,只要能够对齐页面,这样会导致移植性早到破坏。
-- 为了让映射可读可写,一般设定prot参数为PROT_READ | PROT_WRITE。
-- flags参数设定为MAP_ANONYMOUS | MAP_PRIVATE,
-- 当MAP_ANONYMOUS设定时,参数fd和offset会被忽略。
相比malloc之后再设置为memset,calloc会更加方便。
映射/dev/zero
void* p;
int fd;
// 打开/dev/zero以备读取和写入
fd = open("/dev/zero", O_RDWR);
if (fd < 0) {
perror("open");
return 1;
}
// /dev/zero 的【0, page size】映射
p = mmap(NULL, //此时无关紧要
getpagesize(), // 映射一个页面
PROT_READ | PROT_WRITE, // 可写可读
MAP_PRIVATE, // 私有映射
fd, // 映射 /dev/zero
0);
if (p == MAP_FAILED) {
perror("mmap");
if (close(fd))
perror("close");
return -1;
}
//关闭 /dev/zero
if (close(fd))
perror("close");
将字符串复制到堆栈
alloca()常用于临时复制一个字符串
//想要复制 "song"
char* dup;
dup = alloca(strlen(song)+1);
strcpy(dup, song);
//操作dup
return;
#define _GNU_SOURCE
#include <string.h>
char* strdupa(const char* s);
char* strndupa(const char* s, size_t n);
设定字节
#include <string.h>
void* memset(void* s, int c, size_t n);
比较字节
#include <string.h>
int memcmp(const void* s1, const void* s2, size_t n);
此函数会比较s1与s2的前n个字节,如果相等,返回0,如果s1<s2,返回<0的值,如果s1>s2,则返回.>0的值。
移动字节
#include <string.h>
void* memmove(void* dst, const void* src, size_t n);
将src的前n个字节复制到dst,并返回dst.memmove()可以安全处理重叠区域。
#include <string.h>
void* memcpy(void* dst, const void* src, size_t n);
memcpy如同memmove,但是dst和src不可以重叠,如果重叠,则是未定义的。
#include <string.h>
void* memccpy(void* dst, const void* src, int c, size_t n);
memccpy()函数的行为如同memcpy(),但是如果此函数在src的前n个字节中发现了字节c,则停止复制,此函数会返回一个指针,指向dst中的c(如果找不到c,则指向NULL)之后的下一个字节。
最后使用mempcpy(),将数据复制到连续的内存位置。
#define _GNU_SOURCE
#include <string.h>
void* mempcpy(void* dst, const void* src, size_t n);
mempcpy()函数的执行如同memcpy(),但是它会返回一个指针,指向复制的最后一个字节的下一个字节,如果有一组数据想要复制到连续的内存位置,这会很有用。
搜素字节
#include <string.h>
void* memchr(const void* s, int c, size_t n);
#define _GNU_SOURCE
#include <string.h>
void* memrchr(const void* s, int c, size_t n);
旋转字节
#define _GNU_SOURCE
#include <string.h>
void* memfrob(void* s, size_t n);
信号列表
等待任何一个信号
下面的程序会停在pause()处,直到收到一个信号,才会从pause()返回。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
// SIGINT 处理程序
static void SIGINT_handler(int signo) {
printf("Caught SIGINT!\n");
exit(EXIT_SUCCESS);
}
int main(int argc, char** argv) {
/**
* 将SIGINT_handler注册为我们用于处理SIGINT的信号处理程序
*/
if (signal(SIGINT, SIGINT_handler) == SIG_ERR) {
fprintf(stderr, "Cannot handle SIGINT!\n");
exit(EXIT_FAILURE);
}
for(;;) {
pause();
}
return 0;
}
//编译:gcc -o test test.c
执行./test
然后输入Ctrl+C
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
// SIGINT 处理程序
static void SIGINT_handler(int signo) {
if (signo == SIGINT) {
printf("Caught SIGINT!\n");
} else if (signo == SIGTERM) {
printf("Caught SIGTERM!\n");
} else {
fprintf(stderr, "Unexpected signal!\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
int main(int argc, char** argv) {
/**
* 将SIGINT_handler注册为我们用于处理SIGINT的信号处理程序
*/
if (signal(SIGINT, SIGINT_handler) == SIG_ERR) {
fprintf(stderr, "Cannot handle SIGINT!\n");
exit(EXIT_FAILURE);
}
/**
* 将SIGINT_handler注册为我们用于处理SIGTERM的信号处理程序
*/
if (signal(SIGTERM, SIGINT_handler) == SIG_ERR) {
fprintf(stderr, "Cannot handle SIGTERM!\n");
exit(EXIT_FAILURE);
}
/**
* SIGPROF 的行为重置为默认值
*/
if (signal(SIGPROF, SIG_DFL) == SIG_ERR) {
fprintf(stderr, "Cannot handle SIGPROF!\n");
exit(EXIT_FAILURE);
}
/**
* 忽略SIGHUP
*/
if (signal(SIGHUP, SIG_IGN) == SIG_ERR) {
fprintf(stderr, "Cannot handle SIGHUP!\n");
exit(EXIT_FAILURE);
}
for(;;) {
pause();
}
return 0;
}
发送一个信号
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int signo);
给自己发送一个信号
#include <signal.h>
int raise(int signo);
给整个进程组传送一个信号
除了kill,可以使用
#include <signal.h>
int killpg(int pgrp, int signo);
等效于
kill (-pgrp, signo);
保证可重入函数
信号集
#include <signal.h>
int sigemptyset(sigset_t * set);
int sigfillset(sigset_t* set);
int sigaddset(sigset_t* set, int signo);
int sigdelset(sigset_t* set, int signo);
int sigismember(const sigset_t* set, int signo);
linux还提供以下非标准的函数:
#define _GNU_SOURCE
#include <signal.h>
int sigisemptyset(sigset_t* set);
int sigorset(sigset_t * dest, sigset_t* left, sigset_t* right);
int sigandset(sigset_t* dest, sigset_t* left, sigset_t* right);
时间的数据结构
#include <sys/time.h>
struct timeval {
time_t tv_sec; //seconds
susecondes_t tv_usec; //microsecondes
};
#include <time.h>
struct timespec {
time_t tv_sec; //seconds
long tv_nsec; //nanosecondes
};
获取当前时间
#include <time.h>
time_t time(time_t* t);
time_t t;
printf("current time: %ld\n", (long)time(&t));
printf("the same value: %ld\n", (long)t);
#include <sys/time.h>
int gettimeofday(struct timeval* tv, struct timezone* tz);