1.数组
注意:数组下标越界问题
数组初始化:
int arr[5] = {1,2,3} ; 部分初始化,没初始化的默认为0
int arr[5] = { 0 }; 全部清0
获取数组元素个数
printf("sizeof() = %d",sizeof(stu)/sizeof(stu[0]));
数组作函数参数,会转换成指针,也就是在函数内部sizeof(arr)是4
2.字符串
字符串的存储方式:
eg1:char str[20]="hello linux";//字符数组
eg2:char *buf="hello linux";//字符指针
字符串以'\0'结束
strlen(buf)是字符串的有效长度,不包含'\0',sizeof(buf)包括'\0'.
sprintf(str,"hello %d is age = %s",age,name);//字符串格式化
system(char * cmd);
字符串函数头文件<string.h>
字符串函数有:strcpy(),strncpy(),strcat(),strcmp(),strncmp(),strstr(),strlen().
3.函数
void *thread_handle(void* arg)
{
printf("hello\n");
}
int main(int argc,char* argv[])
{
return 0;
}
注意:
1.不可以在函数内部定义放在另外一个函数
2.形参是实参的拷贝本,形参和实参占用不同的内存空间,形参改变不会影响实参。
3.实参和形参:在调用的时候括号中的实际参数,是在内存中存在的。
4.在定义函数的时候,小括号中的参数(有类型)
4.链表
链表:结构体加指针
优点:增加节点、删除节点方便、链表大小可动态增加
缺点:查数据需要遍历链表
struct list_head {
int data;
struct list_head *next,*prev;
};
5.递归
递归:函数自己调用自己
递归的诀窍:
1.需要找到特殊值,(结束值)。
2.找到通用公式。
3.尽量避免定义变量和申请内存
4.一定是要有出口,有return。
6.开关变量和标志位
1、开关变量可用于循环中控制代码块的执行次数。
2、标志位用于判断程序的执行状态
7.标准I/O
标准IO通过操作FILE* 指针对文件进行读写。标准IO创建了缓冲区,以实现减少系统调用的次数。
头文件:#include<stdio.h>
标准IO函数:
fopen(),fscanf(),fprintf(),fread(),fwrite(),fseek(),fclose().
错误处理:
头文件:#include<errno.h>,#include<strerror>
eg:
{
FILE *fp;
if((fp=fopen("hello.txt","a+"))==NULL)
{
perror("fopen error");//不换行,换行不好查看
exit(-1);
}
}
eg:
#include <stdio.h>
int main()
{
char a, b;
while (scanf("%c %c", &a, &b) != EOF)
{
getchar();
printf("%c %c\n", a, b);
}
return 0;
}
使用scanf且输入的是%c时scanf()会读取换行符,使用getchar()获取空格。
8.文件I/O
1.linux一切皆文件,文件描述符是一个索引值,读写文件时需要把文件描述符当做参数进行传递。
2.一个进程启动都会打开三个流,stdin,stdout,stderr;对应文件描述符是0,1,2
写代码时根据函数参数判断,FILE* 是stdin,stdout,stderr;int 是0,1,2。
3.文件IO函数
open(),write(),lseeK(),read(),close();
read()读文件时注意对文件读写位置进行定位。
文件IO函数不带缓冲区。
9.linux多任务编程
1.进程(资源分配的最小单位)
进程之前是独立的,通过特定的通信机制可以实现相互通信。
进程标识符唯一标识一个进程
1.1进程函数
1.fork()
getpid():获取当前进程的id.getppid():获取当前进程夫进程的id.
xxx_t 类型 大部分情况下是unsigned int
注意:子进程没有执行fork()语句,而是fork下一条开始执行。
进程是通过if-else结构实现的。
eg:
pid_t fid=fork();
if(fid<0)
{
perror("fork error");
exit(-1);
}
if(fid>0)
{
此代码块相当于父进程main();
}
if(fid==0)
{
此代码块相当于子进程main();
}
2.exec函数族
调用可执行文件替换当前进程的数据段,代码段,堆栈段。不创建新的进程。
3.exit()和_exit():进程退出函数
exit()函数检测进程打开了哪些文件,将缓冲区的内容写入文件
_exit()直接退出
4.wait()和waitpid():等待进程
wait();wait()使父进程阻塞,等待一个终止的子进程
waitpid();等待一个特定的子进程终止
阻塞:等待需要的资源,释放cpu。被动的,因为得不到资源。
挂起:进程挂起的结果是从内存移到外存,所以挂起不占内存.
因为挂起后还要受到CPU的监督(等待着激活),所以挂起不释放CPU
2.线程(cpu调度的最小单位)
1.线程与同一进程下的其他线程共享进程的内存空间和资源,所以线程的上下文切换比进程小很多。
共享进程内存空间和资源带来的问题,数据谁都可以操作,不能保证它的准确性,需要引入互斥和同步机制。
互斥:一个时间点(很小的时间段)只能有一个线程访问共享数据。
同步:在互斥的基础上按一定的顺序进行访问。
线程是通过函数结构实现的。
2.线程函数
pthread_create()创建线程
pthread_exit()退出线程
pthread_join()等待线程结束
pthread_cancel()主动取消线程
3.线程之间的同步与互斥
互斥锁机制
1.pthread_mutex_init()互斥锁初始化函数
2.pthread_mutex_lock()上锁函数,阻塞
3.pthread_mutex_trylock()判断是否上锁,没上就上锁,上了就立即返回,不阻塞
4.pthread_mutex_unlock()解锁
5.pthread_muxtx_unlock()销毁锁
信号量机制
信号量本质是一个非负整数,用于控制公共资源的访问
PV操作,P减1,V加1
互斥:只设置一个信号量sem
同步:需要设置多个信号量
1.sem_init() 初始化信号量
2.sem_wait() 相当于P操作,阻塞
3.sem_trywait() 相当于P操作,不阻塞
4.sem_post()相当于V操作
5.sem_getvalue()获取信号量的值
6.sem_destroy()删除信号量