c基础
这部分初步学习和了解Linux的使用:
嵌入式开发 环境搭建: 基于Linux 平台的 C语言编程
Linux系统: 是一个操作系统 类似于Windows 侧重于 字符界面 终端命令行模式
Ubuntu系统: 是 一类 Linux 系统 图形界面 与 Windows类似 对新手友好
环境使用:
Ubuntu系统 使用 终端 字符界面
打开终端 右键 打开终端 或 快捷键 ctrl + alt + t
在同一个窗口中 打开多个终端 ctrl + shift + t
vim的使用:
进入vim 处于命令模式:该模式下任何按键都认为是命令
dd 剪切光标所在行
yy 复制光标所在行
p 粘贴
u 撤销
x 删除光标所在字符
i: 在光标 前 插入
a: 在光标 后 插入
o: 在光标 下 新建一行 插入
esc 退出插入模式
底行模式: 输入 : 进入
:wq 保存退出
:w 保存但不退出
:q! 退出且不保存
vim快捷键:
1.全选:ggVG
2.跳转到文本最后一行:shift+g
3.跳转到文本第一行:gg
4.跳转到光标所选行的行尾位置:shift+4
5.gg=G即可对齐
一个简单代码示例:
#include <stdio.h> //头文件 标准输入
int main(){ //主函数 一个c程序的入口
printf("hello world!\n"); //在终端输入字符 "hello world!\n"
return 0; //退出
}
ls -l 显示文件的详细信息:-rwxrwxr-x 1 xwq xwq 8712 6月 29 14:25 a.out
- 表示文件的类型 普通文件 d 表示目录文件 文件夹
C语言中的 基本数据类型:
char 字符类型 、unsigned char 无符号字符类型 、signed char 有符号字符类型
short 半指类型 短整 、int 整型 、long 长整型
float 单精度 浮点型、double 双精度、bool 布尔类型
存储类型:
存储相关的: auto 自动类型(缺省值) 根据变量定义的位置 来自动分配空间
const 修饰变量 改变存储位置到 常量区 或 限制变量的写权限
extern 外部引用存储
register 寄存器存储
static 静态存储
局部变量: 局部的作用域(能访问到该变量的代码区域) 与 局部的 生命周期 (存在的时间)
在代码块内{}定义的 变量 局部变量存放于 栈区, 有程序运行过程中
代码块开始时 自动分配 与 释放 代码块结束时
全局变量: 全局的 作用域(任何位置都可以访问) 有 全局的 生命周期
在函数外, 创建的变量 ,存放于 静态区
程序开始时, 就被创建了 直到程序结束 才会释放
使用三目运算符 求 x,y,z中的最大值
max = x>y?(x>z?x:z):(y>z?y:z);
c高级
这一部分是Linux系统基础
- .指针变量 本质是一个变量 存放的是一个 内存地址
- 内存地址 是一个常量
指针数组 与 二级指针:
指针数组: 一个数组 其元素是 指针
const char * ps[5]; 常量字符串指针数组
const char **p = ps; 二级指针
//指针方式遍历
for(p=ps ; p < ps+5 ; p++) //p+1 移动一个 const char * 类型长度
{
printf("%s ", *p);
}
printf("\n");
- 结构体变量使用:
结构体成员运算符 .
结构体变量.成员名
typedef 关键字 : 类型取别名
以下是计算数组中的最大元素及其下标值的代码:
#include <stdio.h>
void findmax ( int s[ ], int t, int *k )
{
int i;
*k = 0;
for ( i = 1; i < t; i++)
{
if ( s[*k] < s[i] ) *k = i;
}
return ;
}
int main (void)
{
int a[10] = {12, 23, 34, 45, 56, 67, 78, 89, 11, 22}, k;
findmax ( a, 10, &k );
printf ( “ 最大元素为:%d, 其下标值为:%d\n”, a[k], k );
return 0;
}
数据结构
这一部分学习如何更好的写程序
- 数据结构:
是指计算机存储和组织数据的一种方式,相互之间存在一种或多种特定关系的集合
- 常见的时间复杂度:
(1)常量阶____O(1)
(2)线性阶____O(n)
(3)平方阶___O(n^2)
(4)对数阶___O(logn)
- 空间复杂度:表示随问题规模n的增大,算法执行时占用的内存增长率和f(n)的增长率相同
- 线性表的存储方式有两种:顺序存储、链式存储
- 数组分为两种:
静态数组例如:
int arr[10];
动态数组例如:
#define maxsize 10
int *p=(int *)malloc(maxsize *sizeof(int))
memset(void *P,int n,sizeof(*P))//常用它去清空内存空间
以下是创建十个结点的完全二叉树的代码:
#include <stdio.h>
#include <stdlib.h>
// 定义二叉树节点结构
struct Node {
int data;
struct Node *left;
struct Node *right;
};
// 创建新节点
struct Node *createNode(int data) {
struct Node *newNode = (struct Node *)malloc(sizeof(struct Node));
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
// 创建完全二叉树
struct Node *createCompleteBinaryTree(int arr[], int n, int i) {
if (i >= n) {
return NULL;
}
struct Node *root = createNode(arr[i]);
// 递归创建左子树和右子树
root->left = createCompleteBinaryTree(arr, n, 2*i + 1);
root->right = createCompleteBinaryTree(arr, n, 2*i + 2);
return root;
}
// 先序遍历二叉树
void preOrderTraversal(struct Node *root) {
if (root != NULL) {
printf("%d ", root->data);
preOrderTraversal(root->left);
preOrderTraversal(root->right);
}
}
int main() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int n = sizeof(arr) / sizeof(arr[0]);
struct Node *root = createCompleteBinaryTree(arr, n, 0);
printf("先序遍历结果:");
preOrderTraversal(root);
return 0;
}
IO与进程
这一部分学习的是应用层内容
进程是资源管理的最小单位
线程是资源调度的最小单位
程序是进行某项活动或过程所规定的途径
fork()分叉 一个进程的诞生,由从父进程调用fork()而来。
创造出来后的状态是就绪态,等待资源,睡眠态或挂起
只能用于亲缘进程(fok()诞生),无名管道没有名字,只能亲缘进程中去继承文件描述符。
有名字的文件,所以每个进程都能打开,针对所有没有亲缘关系的进程
提供一种带有数据标识的特殊管道,使得每一段被写入的数据都变成带标识的 消息,读取该段消息的进程只要指定这个标识就可以正确地读取,而不会受到其他消息的干 扰,从运行效果来看,一个带标识的消息队列,就像多条并存的管道一样。
是效率最高的 IPC ,因为他抛弃了内核这个“代理人”,直截了当地将一块裸 露的内存放在需要数据传输的进程面前,让他们自己搞,这样的代价是:这些进程必须小心 谨慎地操作这块裸露的共享内存,做好诸如同步、互斥等工作,毕竟现在没有人帮他们来管 理了,一切都要自己动手。也因为这个原因,共享内存一般不能单独使用,而要配合信号量、 互斥锁等协调机制,让各个进程在高效交换数据的同时,不会发生数据践踏、破坏等意外。
信号量 (SEM)
Linux 中用到的信号量有 3 种:ststem-V 信号量、POSIX 有名信号量和 POSIX 无名信号量
以下是写入数据的代码:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <signal.h>
sem_t *space;
sem_t *data;
void trap_signal()
{
sem_close(space);
sem_close(data);
sem_unlink("/mysemspace");
sem_unlink("/mysemdata");
}
int main()
{
int shmid = shmget(ftok("./",1), 2,IPC_CREAT | 0666);//共享内存的大小必须是偶数,实际上在本代码中只需要1个
char *p = shmat(shmid, NULL, 0);//映射
space = sem_open("/mysemspace", O_CREAT, 0666, 1);
data = sem_open("/mysemdata", O_CREAT, 0666, 0);
char *msg = "0123456789";
int i = 0;
signal(SIGINT, &trap_signal);
while(1)
{
//写入数据
sem_wait(space);//空间-1 0个
sleep(1);
memcpy(p, msg+i, 1);
sem_post(data);//数据+1 1个
i = (i+1)%10;
}
}
以下是读数据的代码:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <signal.h>
sem_t *space;
sem_t *data;
void trap_signal()
{
sem_close(space);
sem_close(data);
sem_unlink("/mysemspace");
sem_unlink("/mysemdata");
}
int main()
{
int shmid = shmget(ftok("./",1), 2,IPC_CREAT | 0666);//共享内存的大小必须是偶数,实际上在本代码中只需要1个
char *p = shmat(shmid, NULL, 0);//映射
space = sem_open("/mysemspace", O_CREAT, 0666, 1);
data = sem_open("/mysemdata", O_CREAT, 0666, 0);
signal(SIGINT, &trap_signal);
while(1)
{
//读数据
sem_post(space);
fprintf(stderr, "%c", *p);
sem_wait(data);
}
}
网络编程
这一部分学习的是应用层内容
tcp是一个面向连接,安全,流式协议。
步骤:
1.创建套接字
//创建套接字
int sock_fd = socket(PF_INET,SOCK_STREAM,0);
2.绑定
//绑定地址(IP+PORT)
struct sockaddr_in srvaddr;
srvaddr.sin_family = PF_INET;//地址族
//端口
srvaddr.sin_port = htons(10000); //端口一般取5000以上
//IP地址
srvaddr.sin_addr.s_addr = INADDR_ANY;//将文本字符串转换为32位无符号网络地址
bind(sock_fd,(struct sockaddr *)&srvaddr,sizeof(srvaddr));
3.监听
//设置监听套接字
listen(sock_fd,4);
4.等待连接
//等待客户端连接
printf("等待连接\n");
conn_fd = accept(sock_fd,(struct sockaddr *)&caddr,&addrlen);
printf("[%u]连接成功\n",port);
5.通信
while(1)
{
char msg[100];
bzero(msg,100);
recv(conn_fd,msg,100,0);
if(strcmp(msg, "quit\n") == 0)//quit
{
printf("断开连接\n");
break;
}
printf("recv:%s\n",msg);
}
6.关闭套接字
//关闭套接字
close(conn_fd);
close(sock_fd);
UDP是一种不可靠的、无连接的、数据报服务。
步骤:
1.创建套接字
//创建套接字
int sock_fd = socket(PF_INET,SOCK_DGRAM,0);
2.绑定
//绑定地址(IP+PORT)
struct sockaddr_in srvaddr, cliaddr;
srvaddr.sin_family = PF_INET;//地址族
//端口
srvaddr.sin_port = htons(5555); //端口一般取5000以上
//IP地址
srvaddr.sin_addr.s_addr = INADDR_ANY;//将文本字符串转换为32位无符号网络地址
bind(sock_fd,(struct sockaddr *)&srvaddr,sizeof(srvaddr));
3.通信
while(1)
{
bzero(buf, 100);
bzero(msg, 100);
recvfrom(sock_fd,buf,sizeof(buf),0,(struct sockaddr *)&multiaddr, &addrlen);//先接收
printf("recv:%s\n",buf);
fgets(msg,sizeof(msg),stdin);
sendto(sock_fd,msg,sizeof(msg),0,(struct sockaddr *)&cliaddr, addrlen);
}
4.关闭套接字
close(sock_fd);