内存分配函数
- memcpy(dst, src, size)可以将源目标的指定内存大小复制到目标地址,注意仅仅是复制,并不会为目标地址开辟内存空间,需要为目标地址开辟内存空间才行
//会发生segmention fault 11, 因为dst是一个野指针,未指向任何地址空间int main() {char *src = "hello\0";char *dst;//fix: char *dst = (char*)calloc(strlen(src), sizeof(char));memcpy(dst, src, sizeof(char)*strlen(src));return 0;}
结构体和typedef
struct Person{char *name;int age;};void doWork() {struct Person *p = (struct Person*)malloc(sizeof(struct Person));p->name = "hello\0";printf("%s\n", p->name);}typedef struct{char *name;int age;}Person;void doWork() {Person *p = (Person*)malloc(sizeof(Person));p->name = "hello\0";printf("%s\n", p->name);}
函数返回指针
//注意不要返回局部变量的指针typedef struct{char *name;int age;}Person;Person* doWork() {// Person *p = (Person*)malloc(sizeof(Person));Person tmp;Person *p = &tmp;p->name = "hello\0";printf("%s\n", p->name);return p;}int main() {Person *p = doWork();printf("hellfjiowefew\n"); //如果不要这一句,可能还是正常打印,因为改部分内存可能还没回收printf("%s\n", p->name);return 0;}
free释放内存
//free不会改变传入的指针值,释放后有可能还能访问到该内存数据Person* doWork() {Person *p = (Person*)malloc(sizeof(Person));p->name = "hello\0";printf("%s\n", p->name);free(p);printf("%p\n", p);return p;}
进程和线程
pid_t fork();/*1. 创建一个子进程, 子进程的代码和堆、打开的文件描述符都是和父进程一样的, pid, ppid不一样2. fork方法会有两个返回值, pid_t < 0代表创建失败, 若pid_t=0代表是子进程,pid_t!=0代表是父进程返回*/int execve(const char *path, char const *arg[], char const *envp[]);/*1. 创建进程后用于执行不同的代码段, 该函数有很多变种, 同属于exec族2. v代表包含argv参数数组, e代表可以传递环境变量数据, l代表可以传递不定参数(execl)3. 注意path是可执行的文件, 不能是目录, arg第一个参数是可执行文件名, arg和envp最后一个元素都是NULL*///获取进程和父进程idpid_t getpid();pid_t getppid();//创建线程#include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);//进程管道通信, 返回读写fd#include <unistd.h>int pipe(int fildes[2]);
void start();
int main() { pthread_t tid; int res = pthread_create(&tid, NULL, (void *) start, NULL); if(res < 0) { perror(“pthread_create”); exit(1); } pthread_join(tid, NULL); return 0; }
void start(){ for(int i = 0; i < 5; i++){ printf(“thread %u, %d\n”, pthread_self(), i); } }
<a name="CvpQ9"></a>#### IO操作```c//读写#include <unistd.h>#include <sys/types.h>int open(const char *path, int oflag);//打开文件, oflag是以或的形式组成的标识符int read(int fd, void *buf, size_t nbytes);int write(int fd, void *buf, size_t nbytes);//socket读写#include <sys/socket.h>ssize_t send(int socket, const void *buf, size_t length, int flags);ssize_t recv(int socket, void *buf, size_t length, int flags);//fd复制, dup是在fd表最后一行创建一个新的fd, 指向fildes打开的文件; dup2是将fildes2这个fd//指向fildes这个fd所指向的文件, 相当于关闭fildes2, 把它重定向到fildes#include <unistd.h>int dup(int fildes);int dup2(int fildes, int fildes2);//socket操作#include <sys/socket.h>int socket(int domain, int type, int protocol);//返回fd//将fd绑定到指定端口和ip, sockaddr一般不会传这个类型, 而是scoketaddr_in这个, 它其实是把//sockaddr的第二个字段拆的更细,传入是需要强转, address_len是sockadddr的长度int bind(int socket, const struct sockaddr *address, socketlen_t address_len);int listen(int socket, int backlog);//获取链接, address是传出参数, 用于获取链接的ip等信息, 返回值是链接的fdint accept(int socket, struct sockaddr *address, socklen_t address_len);
cmd
#查看linux c数据结构定义gcc -v #查看c文件所在路径, macos是 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usrgrep -Rn -C 10 -h --include="*.h" --include="*.c" '_opaque_pthread_t {' ./#-C是现实前后n行, -h结果不显示文件名, 一般数据结构是typedef .* pthread或者struct pthread {#这样来查nc -v ip port #建立tcp链接
select
- 注意每次都需要重新传入fd_set,因为select结束后,传入的fd_set会被重置成就绪的fd
- 第一个参数是最大的fd+1
- fd_set的结构是一个long类型数组,每个bit代表一个fd
```c
include
include
include
include
include
include
int main() { fd_set fds; struct timeval tv; tv.tv_sec = 5; tv.tv_usec = 0; FD_ZERO(&fds); FD_SET(0, &fds); FD_SET(1, &fds); int err = select(1, &fds, NULL, NULL, &tv); if(err < 0){ perror(“select”); exit(1); } else if(err == 0){ printf(“chaoshi\n”); } else { printf(“ok\n”); } printf(“isSet %d\n”, FD_ISSET(0, &fds)); return 0; } ```
学习内容
- 进程间通信:mmap,fifo,信号量(父子进程信号量),信号
- nio
- 线程,并发
