内存分配函数

  • memcpy(dst, src, size)可以将源目标的指定内存大小复制到目标地址,注意仅仅是复制,并不会为目标地址开辟内存空间,需要为目标地址开辟内存空间才行
    1. //会发生segmention fault 11, 因为dst是一个野指针,未指向任何地址空间
    2. int main() {
    3. char *src = "hello\0";
    4. char *dst;
    5. //fix: char *dst = (char*)calloc(strlen(src), sizeof(char));
    6. memcpy(dst, src, sizeof(char)*strlen(src));
    7. return 0;
    8. }

结构体和typedef

  1. struct Person{
  2. char *name;
  3. int age;
  4. };
  5. void doWork() {
  6. struct Person *p = (struct Person*)malloc(sizeof(struct Person));
  7. p->name = "hello\0";
  8. printf("%s\n", p->name);
  9. }
  10. typedef struct{
  11. char *name;
  12. int age;
  13. }Person;
  14. void doWork() {
  15. Person *p = (Person*)malloc(sizeof(Person));
  16. p->name = "hello\0";
  17. printf("%s\n", p->name);
  18. }

函数返回指针

  1. //注意不要返回局部变量的指针
  2. typedef struct{
  3. char *name;
  4. int age;
  5. }Person;
  6. Person* doWork() {
  7. // Person *p = (Person*)malloc(sizeof(Person));
  8. Person tmp;
  9. Person *p = &tmp;
  10. p->name = "hello\0";
  11. printf("%s\n", p->name);
  12. return p;
  13. }
  14. int main() {
  15. Person *p = doWork();
  16. printf("hellfjiowefew\n"); //如果不要这一句,可能还是正常打印,因为改部分内存可能还没回收
  17. printf("%s\n", p->name);
  18. return 0;
  19. }

free释放内存

  1. //free不会改变传入的指针值,释放后有可能还能访问到该内存数据
  2. Person* doWork() {
  3. Person *p = (Person*)malloc(sizeof(Person));
  4. p->name = "hello\0";
  5. printf("%s\n", p->name);
  6. free(p);
  7. printf("%p\n", p);
  8. return p;
  9. }

进程和线程

  1. pid_t fork();
  2. /*
  3. 1. 创建一个子进程, 子进程的代码和堆、打开的文件描述符都是和父进程一样的, pid, ppid不一样
  4. 2. fork方法会有两个返回值, pid_t < 0代表创建失败, 若pid_t=0代表是子进程,
  5. pid_t!=0代表是父进程返回
  6. */
  7. int execve(const char *path, char const *arg[], char const *envp[]);
  8. /*
  9. 1. 创建进程后用于执行不同的代码段, 该函数有很多变种, 同属于exec族
  10. 2. v代表包含argv参数数组, e代表可以传递环境变量数据, l代表可以传递不定参数(execl)
  11. 3. 注意path是可执行的文件, 不能是目录, arg第一个参数是可执行文件名, arg和envp最后一个元素都是
  12. NULL
  13. */
  14. //获取进程和父进程id
  15. pid_t getpid();
  16. pid_t getppid();
  17. //创建线程
  18. #include <pthread.h>
  19. int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_
  20. routine)(void*), void *arg);
  21. //进程管道通信, 返回读写fd
  22. #include <unistd.h>
  23. int pipe(int fildes[2]);
  • exit的头文件是stdlib.h ```c

    include

    include

    include

    include

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); } }

  1. <a name="CvpQ9"></a>
  2. #### IO操作
  3. ```c
  4. //读写
  5. #include <unistd.h>
  6. #include <sys/types.h>
  7. int open(const char *path, int oflag);//打开文件, oflag是以或的形式组成的标识符
  8. int read(int fd, void *buf, size_t nbytes);
  9. int write(int fd, void *buf, size_t nbytes);
  10. //socket读写
  11. #include <sys/socket.h>
  12. ssize_t send(int socket, const void *buf, size_t length, int flags);
  13. ssize_t recv(int socket, void *buf, size_t length, int flags);
  14. //fd复制, dup是在fd表最后一行创建一个新的fd, 指向fildes打开的文件; dup2是将fildes2这个fd
  15. //指向fildes这个fd所指向的文件, 相当于关闭fildes2, 把它重定向到fildes
  16. #include <unistd.h>
  17. int dup(int fildes);
  18. int dup2(int fildes, int fildes2);
  19. //socket操作
  20. #include <sys/socket.h>
  21. int socket(int domain, int type, int protocol);//返回fd
  22. //将fd绑定到指定端口和ip, sockaddr一般不会传这个类型, 而是scoketaddr_in这个, 它其实是把
  23. //sockaddr的第二个字段拆的更细,传入是需要强转, address_len是sockadddr的长度
  24. int bind(int socket, const struct sockaddr *address, socketlen_t address_len);
  25. int listen(int socket, int backlog);
  26. //获取链接, address是传出参数, 用于获取链接的ip等信息, 返回值是链接的fd
  27. int accept(int socket, struct sockaddr *address, socklen_t address_len);

cmd

  1. #查看linux c数据结构定义
  2. gcc -v #查看c文件所在路径, macos是 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr
  3. grep -Rn -C 10 -h --include="*.h" --include="*.c" '_opaque_pthread_t {' ./
  4. #-C是现实前后n行, -h结果不显示文件名, 一般数据结构是typedef .* pthread或者struct pthread {
  5. #这样来查
  6. 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
  • 线程,并发