1.数组与*符号在某种情况下等价。
当作为函数的入参的时候,
2.数组变量是指针常量
如下代码,注释掉一行,这一行是不对的,我们知道,字符串是一个存储与字符串常量区的地址。a=“jjj”;表示把这个地址赋值给a ,但是a是一个指针常量,相当于const char *p="hello"
后面是不允许我们作修改的。
char a[]="hello";
printf("%s\n",a);
// a="jjj";
strcpy(a,"jjj");
printf("%s\n",a);
3.ifndef
这个只是防止头文件重复包含,只针对同一个文件多次包含,不是针对所有文件,所以理论上一个变量在头文件定义会导致重复定义的问题
头文件只建议使用声明
//a.h文件声明
extern int a;
//a.c文件定义
int a=0;
//main.c
include "a.h"
关于全局 变量的问题
//a.c文件中,是正确的,这表示声明而已,而不是定义
int a;
int a;
int a;
//但是下面出现=符号表示定义,就不能有多个了。
int a=9;
malloc 是在堆区中分配内存的
变量是存储与栈区,系统是会自动进行回收的。但是对于 malloc 分配的内存,如果不使用free进行释放,会导致内存泄露
结构体可以通过=进行赋值
struct Student p1={12,"blueboz",88};
struct Strudent p2=p1;
//如果使用指针类型,不能
struct Student *p3;
//不能直接进行赋值,否则会导致段错误
p3->age=19;//此行错误
p3=&p1;//才可以操作
//下面直接操作Student里面的info 会导致段错误。因为指针没有指向,最好使用非指针
struct Info{
int age;
char name[50];
};
//1.struct 是关键字
//
struct Student{
int age;
char name[50];
int score;
struct Info *info;
};//有分号
a[0] 与 *(a+0) 与 *(a)是等价的
const修饰的指针
struct Student tmp;
//const 修饰的是* 指针指向的内存无法进行修改
const struct Student *p2=&tmp;
struct Student const *p2=&tmp;
//const 修饰的是p2,指针指向不能修改,但是指针指向的内容是可以修改的
struct Student * const p2=&tmp;
//指针指向无法修改,指针指向的内容也无法修改
const struct Student * const p2=&tmp;
为什么void类型变量不存在而void 类型指针存在
因为对于不同类型的变量,首先我们需要确定的是他占用的空间的大小,但是void类型我们并无法确定,但是对于指针类型却是可以的,因为指针类型占用的空间大小完全由操作系统决定的。对于32位操作系统,指针占用的大小是4字节,对于64位,占用的8字节。
内存四区
堆区,栈区,全局区,代码区。
只要放在大括号里面的变量都是局部变量,只要放在大括号外面的变量都是全局变量。
全局区:全局变量和静态变量,里面分为初始化区和未初始化区。文字常量区:字符常量区。整个程序运行完毕,自动回收。
常量区:字符串常量和其他的常量的存储位置,程序完成之后自动释放。
注意,常量也是放在全局区。
数据类型别名
//定义u32为unsigned int
typedef unsigned int u32;
//定义结构体的别名
typedef struct People{
char name[64];
} People;
数据类型本质
数据类型本质是固定内存大小的别名;是个模具,c语言规定:通过 数据类型定义变量
堆栈的生长方向
先定义的变量拥有高的地址,后定义的有低的地址,但是数组是摆放是按照从低到高的方式。
如图 8c > 88 ,但是有意思的是,数据后定义,居然地址是在高位的?跟书上说的不一样,暂且不深究了。
Mac 实现system(“pause”)
system("read -n 1 -s -p \"Press any key to continue...\"");
字符串反转
通过一个头指针,一个尾指针,相互交换内容效率很高。比传统的递归方式效率要高很多。大概是5倍左右。
/**
* @brief inverse 交换指针指向内容
* @param org
* @return
*/
void inverse(char *org){
//str =012345
int len=strlen(org);
char* start=org;
char* end=org+len-1;
char tmp=0;
while(end>start){
tmp=*end;
*end=*start;
*start=tmp;
end--;
start++;
}
}
查看栈大小
➜ build-dm01-Desktop_Qt_5_13_1_clang_64bit-Debug limit
cputime unlimited
filesize unlimited
datasize unlimited
stacksize 8MB
coredumpsize 0kB
addressspace unlimited
memorylocked unlimited
maxproc 2784
descriptors 2560
导航文章
Linux各类limit设置
指针数组的理解
指针本是一种类型,但又说什么类型的指针,只不过是说指针所指向的 数据是什么类型而已。那么指向数组类型的指针,就只好叫数组指针。
int a[10]; //a的类型是⼀一个指向int类型的指针。
&a; //&a的类型是⼀一个指向数组int[10]类型的指针。
宏定义
要注意,宏定义一般都是直接展开的。遇到if else 语句可能会发生问题。
#define SAFE_DELETE(p) \
do{ \
free(p); \
p=NULL; \
} while(0);
类似如下宏定义就存在着一定的问题。
#define macro(condition) \
if(condition) dosomething()
如果是直接展开,那么就会有问题。
if(temp)
macro(i);
else
doAnotherThing();
else 变成了与macro里面的if 进行结合。这也是为何建议使用do while(0)的原因了。
结构体字节对齐
就算是一样的结构体,但是你定义的位置不一样,导致最终所占用的空间也是不一样的。
struct Sutdent{
double d; //8 8*1=1 2 3 4 5 6 7 8
char c; //1 1*9=9
short s; //2 2*5=11 12
int i; //4 4*3=13 14 15 16
//占用16字节
};
struct Student{
char c; //1*1=1
double d; //8*1=9 10 11 12 13 14 15 16
short s; //2*8=17 18
int i; //4*5=21 22 23 24
//占用24 字节
};
可以采用如下的命令来执行字节对齐。
字节对齐可以程序控制,采用指令:
#pragma pack(xx)
#pragma pack(1)
#pragma pack(2)
#pragma pack(4)
#pragma pack(8)
#pragma pack(16)
//1字节对⻬齐 //2字节对⻬齐 //4字节对⻬齐 //8字节对⻬齐 //16字节对⻬齐
文件操作
其实记住上面的表也很简单,其实核心操作就是r w a 即读写追加
b,只是为了块读写操作。。+表示额外赋权,即写有读,读有写
memwatch 使用
首先是将头原件与源代码引入到项目中。
其次添加宏,可以在qt.pro里面添加,也可以在main.h里面添加。
DEFINES += MEMWATCH
最后是在程序执行地方调用
mwInit();
结束地方调用
mwTerm();
建议看压缩包里面 的USING文档。
动态库的显式调用
在windows平台调用方法。
https://blog.youkuaiyun.com/Hilavergil/article/details/78544424
总结如下
typedef double(SQRTPROC)(double); HINSTANCE hInstance;
SQRTPROC* pFunction;
VERIFY(hInstance=::LoadLibrary("c:\\winnt\\system32\\mydll.dll"));
VERIFY(pFunction=(SQRTPROC*)::GetProcAddress(hInstance,"SquareRoot"));
double d=(*pFunction)(81.0);//调⽤用该DLL函数
在linux mac平台下的调用方法
https://blog.youkuaiyun.com/lc_910927/article/details/42393121
总结几句
1.导入
#include <dlfcn.h>
2.其次,编译的时候导入-ldl库即libdl.dylib (mac)或者 libdl.so(linux)
#LIBS += -ldl
//打开动态库
void *hand = dlopen(fullpath,RTLD_NOW);
//定义函数指针
typedef void (*SAYMYNAME)();
//从handler 里面获得函数地址,并且转化成函数指针
SAYMYNAME p1=(SAYMYNAME)dlsym(hand,"sayMyName");
//执行函数调用
p1();
//关闭
dlclose(hand);
//查错
char err=dlerror();