linux学习笔记
头文件防止定义多个
#pragma once
#ifdef _MAIN_H
#define _MAIN_H
#endif
地址的存储,32位编译器用32位存地址,64位编译器使用64位存地址
野指针:存着没有意义地址的指针
注意传的时候要把长度也传进去,因为是不可知的
对编译器而言,int a[1000], int a[], int *a对于编译器而言,没有任何区别,都是当做int *处理
二维数组不是二级指针,
打印字符串传入参数为%s, 传入第一个值的地址,然后继续寻找直到结束符号,不然就会乱码
static修饰的变量在编译阶段就进行初始化
static 修饰的局部变量初始化只会执行一次,可以赋值多次
static 修饰的局部变量只能用常量进行初始化,因为他会先初始化,这时候局部变量还没有入栈,所以只能使用常量进行初始化
static修饰的变量只有在整个程序结束才会进行初始化
普通的全局变量:
在{}函数外面定义的全局变量称之为全局变量,只有外面定义了全局变量,任何地方都能用到,
如果使用之前还没有定义,需要声明,
如果定义一个全局变量,没有初始化,这个肯定是定义,
定义全局变量初始化,声明全局变量就使用extern
全局变量分文件:
头文件只使用头文件做声明extern
static全局变量:
一个文件只能有一个static全局变量的定义,一个文件不能出现多个
static全局变量相对于普通全局变量只能在本文件中使用
普通全局变量:外部连接
static全局变量:内部连接
全局变量的寻找:就近原则
程序没有运行之前内存分区已经确定,虽然分区确定,但是没有加载内存,程序只有在运行的时候才能加载内存
text(代码区):只读,函数
data:初始化的数据,全局变量,static变量,文字常量区(只读)
bss:没有初始化的数据,全局变量,static变量
当程序运行时,加载内存,首先根据前面确定的内存分区(text,data,bss)先加载,然后额外加载2个区
stack(栈区):普通局部变量,自动管理内存,先进后出
heap(堆区):手动申请空间,手动释放,整个程序结束,系统也会自动回收
使用size a.out查看程序的各个部分的占比
ulimit查看栈的大小有多大
内存使用的几个函数
memset
将内存区域的前几个字符以..的方式填写,中间参数是以字符处理.
优越性:当改变了字符数组的时候,如果不用这个办法,就需要获取长度,循环赋值0
memcpy
相对于strcpy,全部拷贝,而不是像str遇到\0就结束拷贝
此函数的使用不要出现内存重叠
memmove
如果出现内存重叠,就使用这个函数
memcmp
为什么和str*系列区分:因为str遇到\0就会结束,mem使用范围更广泛
free的使用和判空进行使用,避免重复释放问题
if(NULL != p)
{
free(p);
p = NULL;
}
高位放高地址,低位放低地址,叫做小端,指针总是从低地址向高地址进行存储
typedef 起别名
文件操作流程:
- 打开文件fopen
- 读写文件
- 按照字符读写fgetc(), fputc()
- 按照字符串行读取文件 fgets() fputs()
- 按照文件结尾符号 feof
- 关闭文件 fclose()
fopen 的选项,如果r,文件不存在,打开就会失败,”w”如果文件不存在就会新建,存在就会清空内容打开,”a”文件不存在,新建,如果文件存在,光标放在文件末尾
linux相对路径是对于可执行程序,相对路径
VS , 编译同时运行程序,相对于.vcxproj所在的路径
如果直接运行程序,就是相对于可执行程序
/*
c demo
*/
//常用的头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
/*
56 34 12 00
^
|
p
指针指向这个位置
指针步长demo
*/
void demo1()
{
int i = 0;
int a = 0x00123456;
void *p = &a;
printf("%x\n", *(char *)p);
char *tmp = (char *)p;
for (i = 0; i < 4; i++)
{
printf("%x\n", *tmp);
tmp = tmp + 1;
}
}
/*
const修饰指针
*/
void demo2()
{
int a = 1;
int *const p = &a;
//编译失败,表示p(保存地址)无法被更改,只能指向这个地址
// p = NULL;
int const *p1 = &a;
const int *p2 = &a;
a = 2;
p1 = NULL;
p2 = NULL;
}
/*
指针操作数组
*/
void demo3()
{
int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int *p = a;
int len = sizeof(a) / sizeof(*a);
int i = 0;
for (i = 0; i < len; i++)
{
printf("%d\n", *p);
p++;
}
printf("\n\n");
p = &a[len - 1];
for (i = 0; i < len; i++)
{
printf("%d\n", *p);
p--;
}
}
/*
指针数组:是数组,每个元素都是指针
数组指针:指向数组的指针
*/
void demo4()
{
int a[3] = {0, 1, 2};
int *p[3];
// p[0] = &a[0]
p[0] = a;
// p[1] = a+1;
p[1] = &a[1];
// p[2] = a+2;
p[2] = &a[2];
int len = sizeof(a) / sizeof(*a);
int i = 0;
for (i = 0; i < len; i++)
{
printf("%d\n", *p[i]);
}
}
/*
值传递,指针传递
不要被c++的引用混淆了
c没有引用
*/
void swap(int a, int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
void swap2(int *a, int *b)
{
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
void demo5()
{
int a = 10;
int b = 20;
swap2(&a, &b);
printf("%d\n", a);
printf("%d\n", b);
}
/*
形参中的数组demo
注意传的时候要把长度也传进去,因为是不可知的
对编译器而言,int a[1000], int a[], int *a对于编译器而言,没有任何区别,都是当做int *处理
*/
void sort(int *a, int len)
{
int i = 0;
int j = 0;
for (i = 0; i < len - 1; i++)
{
for (j = 0; j < len - 1 - i; j++)
{
if (a[j] > a[j + 1])
{
swap2(&a[j], &a[j + 1]);
}
}
}
}
void demo6()
{
int a[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
int len = sizeof(a) / sizeof(*a);
sort(a, len);
int i;
for (i = 0; i < len; i++)
{
printf("%d--", a[i]);
}
printf("\n");
int *p;
printf("%d\n", sizeof(p));
}
/*
字符串拼接
*/
int demo7()
{
char str[] = "hello";
char str2[] = "world";
strcat(str, str2);
printf("str is %s \n", str);
}
/*
字符串打印的乱码测试
*/
void demo8()
{
char a[] = {'a', 'b'};
int i;
char *p = a;
for (i = 0; i < 4; i++)
{
printf("char is %d \n", *p);
p++;
}
printf("%s\n", a);
}
/*
字符串使用const修饰
整个字符串都会被赋予只读
*/
void demo9()
{
char a[] = {'a', 'b'};
const char *p = a;
//*p = 'k'; err
p++;
//*p = 'k'; err
}
/*
字符串常量地址
存放在data区域,不可以修改
*/
void printStr()
{
printf("%p\n", "helloworld");
}
void demo10()
{
printf("%s\n", "helloworld");
printf("%p\n", "helloworld");
printf("%s\n", "helloworld" + 1);
printStr();
char *p = "helloworld";
printf("%s\n", p);
//*(++p) = 'a'; err
}
/*
main函数的参数意义
*/
// void fun1(int a[10])
// void fun1(int a[])
// void fun1(int *a) 都是一样的
void printArray(char **p, int n)
{
int i;
for (i = 0; i < n; i++)
{
printf("the %dth is %s\n", i, p[i]);
}
}
void demo11()
{
char *p1 = "hello";
char *p2 = "world";
char *p3 = "lx";
char *p[] = {p1, p2, p3};
int n = sizeof(p) / sizeof(p[0]);
int i;
for (i = 0; i < n; i++)
{
printf("%s\n", p[i]);
}
}
/*
二维数组的使用方式
*/
void printfArray2(char **a, int n)
{
int i;
for (i = 0; i < n; i++)
{
printf("%s\n", a[i]);
}
printf("\n");
}
void demo12()
{
char *a[] = {"aa", "bb", "cc", "dd"};
int n = sizeof(a) / sizeof(*a);
printfArray2((char **)a, n);
}
/*
查找字符串匹配次数的方式
*/
void demo13()
{
char *p = "11abc33333abc55555abc1111abc666";
int i = 0;
char *tmp = NULL;
while (1)
{
tmp = strstr(p, "abc");
if (NULL == tmp)
{
break;
}
else
{
printf("%s\n", tmp);
p = tmp + strlen("abc");
}
}
}
/*
二维数组的赋值操作
*/
void demo14()
{
int a, b, c;
int *p12[] = {&a, &b, &c};
//表现1
char *str1 = "abc";
char *str2 = "hello";
char *str3 = "mike";
char *p[] = {str1, str2, str3};
//表现2
char *p1[] = {"abc", "hello", "mike"};
//表现3
char *p2[3];
p2[0] = "abc";
p2[1] = "hello";
p2[2] = "mike";
printfArray2(p, 3);
printfArray2(p1, 3);
printfArray2(p2, 3);
}
/*
static demo
static 修饰的局部变量初始化只会执行一次,可以赋值多次
static 修饰的局部变量只能用常量进行初始化,因为他会先初始化,这时候局部变量还没有入栈,所以只能使用常量进行初始化
*/
void static_func()
{
static int i = 0;
i++;
printf("static_func i = %d\n", i);
}
void demo15()
{
static_func();
static_func();
static_func();
}
/*
memset
memcpy demo
*/
void demo16()
{
char p[] = "hello\0mike";
char buf[100];
printf("sizeof(p) = %lu\n", sizeof(p));
strncpy(buf, p, sizeof(p));
printf("buf1 = %s\n", buf);
printf("buf2 = %s\n", buf+strlen("hello")+1);
memset(buf, 0, sizeof(buf));
memcpy(buf, p, sizeof(p));
printf("buf1 = %s\n", buf);
printf("buf2 = %s\n", buf+strlen("hello")+1);
}
/*
memcpy 常用
*/
void demo17()
{
char a[] = {1,2,3,4,5,6,7,8,9};
char b[9];
memcpy(b, a, sizeof(a));
//or memcpy(b, a, sizeof(int)*9);
//内存重叠:不可以出现
memcpy(&a[2], a, 5*sizeof(int));
}
/*
memmove 常用
*/
void demo18()
{
int a[] = {1,2,3,4,5,6,7,8,9};
memmove(&a[2], a, 5*sizeof(int));
int len = sizeof(a)/sizeof(a[0]);
printf("len is %d\n", len);
int i;
for(i=0;i<len;i++)
{
printf("%d\n", a[i]);
}
}
/*
stack demo
*/
void demo19()
{
int *p;
int a;
p = &a;
*p = 10;
printf("*p = %d\n", *p);
}
/*
内存对齐
*/
struct Stu
{
char ID;
int age;
short k;
};
typedef struct Stu1
{
char ID;
int age;
int k;
}STU;
void demo20()
{
printf("the size of the struct is %d\n",sizeof(char)+sizeof(int)+sizeof(short));
printf("the size of the struct is %d\n", sizeof(struct Stu1));
}
/*
完全相同的结构体可以赋值
*/
void demo21()
{
struct Stu stu1 = {1,2,3};
struct Stu stu2 = stu1;
}
/*
union demo
*/
union Tea
{
unsigned char ID;
unsigned int a;
};
void demo22()
{
union Tea tea;
tea.ID = 'a';
printf("the size of the struct is %d\n", sizeof(union Tea));
}
/*
typedef demo
*/
void demo23()
{
STU student;
student.age = 12;
}
/*
文件描述符的使用,印证按照顺序寻找空闲fd
*/
void demo24()
{
close(1);
int fd = open("01.txt", O_RDWR|O_CREAT, 0777);
printf("today i am so happy\n");
printf("today i am so happy\n");
printf("today i am so happy\n");
printf("today i am so happy\n");
}
/*
文件读写
*/
void demo25()
{
FILE *fp = NULL;
fp = fopen("./01.txt", "rw");
if(NULL == fp)
{
perror("fopen");
return;
}
}
/*
fputc的使用
*/
void demo26()
{
FILE* fp = NULL;
fp = fopen("./02.txt", "w");
if(NULL == fp)
{
perror("open");
return -1;
}
char buf[] = "hello world\n";
int len = strlen(buf);
int i;
for(i=0;i<len;i++)
{
fputc(buf[i], fp);
}
fclose(fp);
}
int main(int argc, char *argv[])
{
demo26();
#if 0
printArray(argv, argc);
#endif
return 0;
}