Linux命令基础
1. Linux文件类型(bsp_lcd)七种
b:块(block)设备文件:存储设备(硬盘、SD卡) /dev/sd
s:套接字(socket)文件:网络编程
p:管道(pipe)文件:I/O编程
-:普通文件:.c文件 .h文件 .txt文件
l:软连接文件:类似快捷方式
d:目录(dirctor)文件:文件夹
c:字符设备文件:鼠标、键盘 /dev/input/mouse
2. Linux文件权限
chmod命令用于修改文件权限
eg.
chmod 777 file // 修改file文件的权限为用户、组内成员、其他用户均可读可写可执行
rwx rwx rwx 分别是(用户、组内成员、其他用户)
1. mkdir创建文件夹命令
常用的3个命令:
1.mkdir 目录名 // 创建一个空目录文件
eg. mkdir test //在当前路径下创建一个名为test的目录
2.mkdir –p 绝对路径/目录名 // 在绝对路径中去创建一个空目录文件,如果该绝对路径下目录存在则直接在这个已存在的目录中去创建一个为目录名的空目录文件,如果该绝对路径下目录不存在,则直接在该绝对路径下去创建这个目录然后在这个目录下直接创建目录名的空目录文件
eg. mkdir –p /home/stu/Desktop/New/test // 在绝对路径为/home/stu/Desktop/New/的目录下创建一个名为test的新目录, New可以不存在
3.mkdir 目录名1 目录名2 目录名3 …… // 直接在当前位置创建目录名1和目录名2两个空目录文件,甚至可以更多
2. touch新建文件命令
touch [OPTION]… FILE…
如果当前目录下有同名文件,touch命令会更新时间戳,但不会修改内容
3. rm删除文件/目录命令
rm -r 目录文件名 —— 删除目录文件
rm 文件名.后缀 —— 删除普通文件
rm -rf 目录文件名 —— 强制删除目录文件
4. cp复制文件/文件夹命令
常用3个命令:
1.cp 文件名 目标路径 // 复制普通文件
2.cp -r 目录名 目标路径 // 复制目录文件
3.cp 文件名 路径/新文件名 // 另存为
5. cd切换路径命令
常用3种命令:
1. cd+路径
2. cd+绝对路径 // 从根目录开始索引
3. cd+相对路径 //从相对于当前的路径开始索引
常见参数:
. 表示当前
.. 表示上一级
~ 家目录
/ 根目录
- 上一次的路径
gcc编译
gcc -o 可执行文件名 源文件名
gcc -E 可执行文件
数据类型
使用bool类型需要添加语句
#include<stdbool.h>
vscode
int main(int argc, const char *argv[])
#argc是命令行总的参数个数;argv[]为保存命令行参数的字符串指针,其中第0个参数是程序的全名,以后的参数为命令行后面跟的用户输入的参数,argv参数是字符串指针数组,其各元素值为命令行中各字符串(参数均按字符串处理)的首地址。 指针数组的长度即为参数个数argc。数组元素初值由系统自动赋予。
也就是说,argv[i]是指向char类型的指针数组,指向char类型的i的首地址。而*char[i]就是指i这个字符串类型的内容
运算符及其次序
x++ 是指,先拿到x的值,然后再对x的值进行+1的操作
++x 是指,先对x的值进行+1的操作,再拿到x的值。
指针
存储类型是指针变量本身的存储类型(一般是auto)
定义的指针要与所指向的变量类型相同
不进行初始化会产生野指针
指针修饰
修饰为只读模式,不可在函数内进行修改,会直接报错!
如果真的想修改,可以操作指针,取值操作进行修改
const int a = 10; // const修饰a
a = 20; // Error:Readonly
int a = 10, b = 20;
const int *p = &a; // const修饰*p
*p = 20; // Error:const修饰*p
p = &b; // 可以操作:可以改变指针指向
int *const p; // 修饰p,指针指向不能修改,但指针内容可以修改
*p = 20; // 可以操作
p = &b; // Error:不可以改变指针指向
const后是谁就修饰的是谁,修饰的内容不可以更改!
void *p; //表示任意类型的指针,不是空类型
void a; // Error:不可以修饰变量
大小端
大端:低地址存高字节
小端:低地址存低字节
1. 指针运算:对地址量进行运算
二级指针(存放地址的地址)
int a = 10;
int *p = &a;
int **q = &p; // 二级指针
2. 指针与数组
指针与二维数组
*(a + 1) = a[1]; //两者等价
由原来的移动一行到改变后的移动一列
行指针(数组指针)
存储行地址的指针变量,叫做行指针变量
<存储类型> <数据类型> (*<指针变量名>)
int a[2][3] / int (*p)[3] // p的类型是int (*)[3] 运算步长为3
p = a;
printf("%d %d %d\n", a[1][1], p[1][1], *(*(a+1)+1));
// 三者表示元素相同,第三个先对a+1表示a前进一行,*括起来改变指针性质,行指针变成一级指针,后+1表示移动1列,再取值
3. 指针数组
本质是一个数组,数组元素是地址
int *a[n]; //
argv:指针数组,用来存放命令行传递的字符串
argc:表示argv中存储数据的个数,即命令行输入字符串的个数
4. 数组指针
函数
1. 定义格式
<返回值数据类型> <函数名> (<形式参数说明>){
语句序列;
return (<表达式>);
}
2. 调用格式
函数名称(<实际参数>) // 实际参数可以是若干个变量,也可以是若干个表达式
3. 参数传递
1. 值传递方式(常用)
调用函数将实参传递给被调用函数,被调用函数将创建同类型的形参并用实参初始
化;形参是新开辟的存储空间,因此改变形参不会影响实参,相当于实参赋值给形参
void func(int a, int b){ // int a = x, b = y;
// ...
}
int main(){
int x, y;
func(x,y); //直接赋值操作
}
2. 地址传递方式(常用)
void func(int *a, int *b){
// ...
}
int main(){
int x, y;
func(&x, &y); //直接传递地址
}
3. 全局变量传参
将变量定义在所有函数外,同名变量全局皆可使用与修改,不建议使用
4. 数组传参
int array_sum(int data[]); //形参为数组名,本质上是 int *data = a;
int array_sum(int *data); // 本质也是一个数组指针
5. 动态开辟堆区空间
#include<stdlib.h>
void *malloc(size_t size);
void free(void *ptr);
free(p);
p = NULL;
malloc:在堆区开辟参数size大小空间,开辟成功返回开辟空间首地址;失败返回NULL
free:释放堆区ptr首地址空间
如果在子函数中开辟堆区空间,想在main函数拿到首地址有两种方式:返回值、地址传递
// 返回值传递 #include <stdio.h> #include <stdlib.h> #include <string.h> char *fun() { char *p = (char *)malloc(32);// 栈区定义一个指针p指向堆区开辟的空间的首地址 strcpy(p, "hello"); return p; // 返回的是一个地址而不是指针,就是一串数字代表地址 } int main() { char *m =fun(); // 这里直接栈区定义 printf("%s\n", m); free(m); m=NULL; return 0; }
// 地址传递 #include <stdio.h> #include <stdlib.h> void fun(char **p) // p = &m //*p == m { *p = (char *)malloc(32); //m指向堆区空间首地址 strcpy(*p, "hello"); } int main() { char *m = NULL; fun(&m); printf("%s\n", m); free(m); m = NULL; return 0; }
5. string函数族
strcpy/strncpy函数
#include <string.h>
char *strcpy(char *dest, const char *src);
// src源字符串(const修饰不可更改);
// dest目标字符串
// 将源字符串复制给目标字符串
char *strncpy(char *dest, const char *src, size_t n);
// src源字符串(const修饰不可更改);
// dest目标字符串
// 将源字符串的前n个字符复制给目标字符串
该函数会覆盖目标字符串的对应字节长度的数据,例如
#include<string.h>
int main(){
char dest[32] = "hellohello";
char src[] = "world";
strcpy(dest,src);
// 此时输出dest会显示“world",但其实只是占用了dest串的前6位(包含'\0'),后面还有"ello",只不过遇到'\0'就结束了
strncpy(dest,src,3);
}
复制函数的原理如下
char *my_strcpy(char *dest, char *src){
char *p = dest;
while(*src){
*dest = *src;
dest ++;
src ++;
}
return p;
}
char *my_strncpy(char *dest, char *src, int n){
char *p = dest;
while(n){
*dest = *src;
dest ++;
src ++;
n--;
}
return p;
}
strlen函数
size_t strlen( const char *string );
strlen是一个函数,属于cstring库,用于计算指定字符串str的长度,不包括‘\0’
sizeof是一个单目运算符,它的参数可以是数组、指针、类型、对象、函数等,sizeof在计算字符串长度时会包括‘\0’
strcat/strncat函数
#include <string.h>
char *strcat(char *dest, const char *src);
// src源字符串(const修饰不可更改);
// dest目标字符串
// 将源字符串拼接在目标字符串后,前提不可以越界,越界会直接报错
char *strncat(char *dest, const char *src, size_t n);
// src源字符串(const修饰不可更改);
// dest目标字符串
// 将源字符串的前n位拼接在目标字符串后,前提不可以越界,越界会直接报错
strcmp/strncmp函数
#include <string.h>
int *strcmp(char *string1, const char *string2);
// 将源字符串1与字符串2按字符的ASCII码值进行比较
// 第一个字符串大于第二个字符串,则返回大于0的数字
// 第一个字符串等于第二个字符串,则返回0 if(!strcmp(s1,s2)){}
// 第一个字符串小于第二个字符串,则返回小于0的数字
int *strncmp(char *string1, const char *string2);
// 将源字符串1与字符串2的前n个字符按字符的ASCII码值进行比较
// 第一个字符串大于第二个字符串,则返回大于0的数字
// 第一个字符串等于第二个字符串,则返回0 if(!strcmp(s1,s2)){}
// 第一个字符串小于第二个字符串,则返回小于0的数字
6. 指针函数
本质:函数,函数的返回值为指针
数据类型 *函数名(参数){
...
return 地址;
//return NULL;
//return 0;
//return -1;
}
*void malloc(size_t size);
*void free(void ptr);
7. 函数指针
本质:指针,指向函数的指针
格式:数据类型 (*函数指针变量名)(参数);
用法:
8. 函数指针数组
本质:数组,数组的内容为函数指针,但局限性太强,必须函数返回值个数和类型均相同
格式:数据类型 (*函数指针数组名[下标])(参数);
#include <stdio.h>
int add(int a, int b);
int sub(int a, int b);
int mul(int a, int b);
int main(int argc, const char *argv[])
{
//数组:函数指针数组
int (*st[])(int,int) = {add,sub,mul}; //4*3 = 12
//int st[5]; sizeof(st)
//add(3,4)
//st[0](3,4);
//st[0] = add; //数组名[下标],st[1] = sub;
int i;
for(i = 0; i < sizeof(st)/sizeof(st[0]); i++)
{
printf("%d\n",st[i](4,3));//实参
}
return 0;
}
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
9. 递归
两个阶段:
10. 结构体
结构体定义
常规定义
struct 结构体名{
数据类型 变量名;
...
};
struct 结构体名 结构体变量名;
typedef法(取别名)
typedef struct student {
int num;
char name[20];
char sex;
}stu, * pstu;
// 给结构体类型起别名,叫stu,起了结构体指针类型的别名,叫pstu
typedef int INTEGER;
// 使用typedef可以对常规变量起别名
INTEGER i = 10; // 使用时直接使用别名定义
理论上讲结构体的各个成员在内存中是连续存放的,和数组非常类似,但是,结构体占用内存的总大小不一定等于全部成员变量占用内存大小之和。在编译器的具体实现中,为了提高内存寻址的效率,各个成员之间可能会存在缝隙。用sizeof可以得到结构体占用内容在总大小,sizeof(结构体名)或sizeof(结构体变量名)都可以。
11.共用体
union 共用体名{
成员列表
};
12. 枚举类型
用来声明一组常数的用户自定义类型,用于提高代码的可读性
#include <stdio.h>
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
int main()
{
enum DAY day;
day = WED;
printf("%d",day);
return 0;
}
13. 存储类型
auto(自动型):修饰局部变量,局部变量省略存储类型会默认auto
static(静态型):可以修饰变量和函数
变量存放的位置在全局区(静态区)有初值存放.data区域,没有初值存放.bss区域
生命周期为整个程序
限制作用域
修饰局部变量:和普通局部变量的作用域没有区别,但是可以延长生命周期
修饰全局变量:限制在本文件中使用
只初始化一次,没有赋初值置为0
extern(外部引用):通过extern引用其他文件的全局变量或函数
有符号数与无符号运算时数强制类型转换方式及底层表示
#include <stdio.h>
int main(){
int a = -1;
unsigned int b = 1;
if(a > b)
printf("a > b, a = %d, b = %u\n", a, b);
else
printf("a <= b, a = %d, b = %u\n", a, b);
exit(0);
} // 输出a > b
当执行一个运算时(如这里的a>b),如果它的一个运算数是有符号的而另一个数是无符号的,那么C语言会隐式地将有符号参数强制类型为无符号数,并假设这两个数都是非负的,来执行这个运算。这种方法对于标准的算术运算来说并无多大差异,但是对于像<和>这样的运算就可能产生非直观的结果。