zedu小语种网站建设,wordpress 开发指南,网络推广员工资多少钱,天元建设集团有限公司商票拒付内存地址
将内存抽象成一个很大的一维字符数组#xff0c;编码就是对内存的每一个字节分配一个32位或64位的二进制编号。这个内存编号称之为内存地址#xff08;唯一#xff09;#xff0c;内存中的每一个数据都会分配相应的地址。 #includeiostream
using namesp…内存地址
将内存抽象成一个很大的一维字符数组编码就是对内存的每一个字节分配一个32位或64位的二进制编号。这个内存编号称之为内存地址唯一内存中的每一个数据都会分配相应的地址。 #includeiostream
using namespace std;
int main()
{int num 10;cout num endl;cout sizeof(num);//32位系统分配32位编码4个字节//64位系统分配64位编码8个字节return 0;
} 注意这里的地址是8个字节 地址用16进制的数表示一位16进制数表示4位的二进制数2^4 16 如8:1000 9:1001 A:1010 B:1011 指针和指针变量 指针和intdouble等类似是一种独立的数据类型。这种类型的变量存储的值是内存地址。
指针变量本质就是变量只是该变量存储的是内存地址而不是普通的数据。不同类型的指针变量所占用的存储单元长度是相同的。 #includeiostream
using namespace std;
int main()
{int* p1 nullptr;int num 10;cout sizeof(num) endl;//这个表示num的数据类型int在电脑中占4个字节cout sizeof(p1) endl;//指针内存地址8个字节cout sizeof(*p1) endl;//加了一个*,解引用表示指针所指向的int类型的值cout p1 endl;//存储这个整型指针的地址cout sizeof(p1) endl;cout (*p1) endl;//指针所指向的地址return 0;
} 野指针
指的是没有被初始化过的指针。指针变量未初始化时不会自动成为 nullptr而是一个随机值。
int main() { int* p; // 未初始化std::cout *p std::endl; // 未初始化就被使用return 0;
}
因此为了防止出错对于指针初始化时都是赋值为 nullptr这样在使用时编译器就会直接报错产生非法内存访问。
悬空指针
悬空指针指针最初指向的内存已经被释放了的一种指针。指针操作超越变量的作用域比如函数返回栈内存的指针或引用
int main() { int * p nullptr;int* p2 new int;p p2;delete p2;
}
此时 p和p2就是悬空指针指向的内存已经被释放。继续使用这两个指针行为不可预料。需要设置为pp2nullptr。此时再使用编译器会直接保错。
野指针和悬空指针无法通过简单地判断是否为 nullptr 避免所以要习惯在初始化时赋值或析构时赋为nullptr。
void*是一种特殊的指针类型可以存放任意对象的地址但不能直接操作void*指针所指的对象。
指针与数组名的区别 修改内容上的差别
char a[] hello;
a[0] H;
char *p world; // p 指向常量字符串该字符串存储在文字常量区不可更改
// p[0] W // 所以这个赋值有问题 “world” 是const char*类型不可更改
如果要改用下面的数组先定义然后再改。
int main() {char a[] hello;char *p a; // 这样让指针指向数组 a而非常量字符串就可以修改了p[0] H;a[1] E;printf(%d, sizeof(p)); // 64 位机器std::cout p std::endl; return 0;
}
//输出8HEllo
数组指针与指针数组
type (*p)[]; // 数组指针
/*
type a[]a 是一个数组数组内元素都是 type 类型将 a 换成 (*p)
可以理解为 *p是一个数组数组内元素都是 type 类型那么 p 就是指向这样的数组的指针即数组指针。
*/type *p[]; // 指针数组
/*
type *p[]即(type *)p[]则 p 是一个 type* 类型的数组(类比int a[10]a 是 int 型数组
即 p 是一个数组数组内元素都是指针 type *
*/
const int seq_cnt 6;
vectorint *seq_addrs[seq_cnt] {fibonacci, lucas, pell,triangular, square, pentagonal
};
// seq_addrs 是一个数组存储 vectorint * 型的指针
// seq_addrs[0] 的内容为指针该指针指向 fibonacci
// 而 fibonacci 的类型为 vectorint。EssentialC 29
指针函数与函数指针
指针函数返回类型是指针的函数如
char *StrCat(char *ptr1, char *ptr2)
{char *p;do something;return p;
}
函数指针指向函数的指针如
#include stdio.h
int max(int x, int y)
{return x y? x: y;
}
int main()
{// int max(int x, int y);int (*ptr)(int, int);ptr max;int max_num (*ptr)(12, 18); // int max_num ptr(12, 18);也是对的printf(%d, max_num);return 0;
}
// 打印 18。
int (*ptr)(); // “()” 表明该指针指向函数函数返回值为 int
int (*ptr)[3]; // “[]” 表明该指针指向一维数组该数组里包含三个元素每一个元素都是int类型。
数组名指向了内存中一段连续的存储区域可以通过数组名的指针形式去访问也可以定义一个相同类型的指针变量指向这段内存的起始地址从而通过指针变量去引用数组元素。
每一个函数占用一段内存区域而函数名就是指向函数所占内存区的起始地址的函数指针地址常量故函数指针解引用与不解引用没有区别 。通过引用函数名这个函数指针让正在运行的程序转向该入口地址执行函数的函数体也可以把函数的入口地址赋给一个指针变量使该指针变量指向该函数。 解读复杂指针使用右左法则首先从未定义的标识符所在的圆括号看起然后往右看再往左看。每当遇到圆括号就调转阅读方向。一旦解析完圆括号里的东西就跳出圆括号。重复这个过程直到整个声明解析完毕。
int (*func)(int *p, int (*f)(int*));
// func左边有一个*表明func是一个指针跳出圆括号看右边右边有括号说明func是一个函数指针
// 指向的函数接收两个形参分别是整型指针 int * 和函数指针 int (*f)(int*)返回值为 int。int (*func[5])(int *p);
// func 是一个数组含5个元素左边*号表明 func 是一个指针数组由于[]优先级高于*func先跟[]结合然后*修饰func[5]故该数组的元素都是指针。
//再往右看是括号说明 func 里的指针是函数指针函数指针所指向的函数接收 int * 型参数并返回 int。int (*(*func)[5])(int *p);
// func 是一个指针指向含有 5 个元素的数组数组里的元素都是指针而且都是函数指针
// 函数指针指向的函数接收 int * 型形参并返回 int。int (*(*func)(int *p))[5];
// func 是一个指针该指针指向一个函数该函数接收 int * 型参数返回一个指针
// 返回的指针指向一个数组该数组含有 5 个元素每一个元素都是 int 型。
常引用作为函数参数
如果既要利用引用提高程序的效率又要保护传递给函数的数据不在函数中被改变就应使用常引用
void foo(const string s) {cout s endl;
} // 如果形参里的 const 去掉程序就报错
// 因为 ss 与 world! 都是常量你不能把一个 const 类型转换成非 const 类型。
// 所以 foo() 形参必定要用 const 修饰。int main() {const string ss(hello );//此处有const,且“hello”本来就是一个常量foo(ss);foo(world!);
}
对于常量类型的变量其引用也必须是常量类型的对于非常量类型的变量其引用可以是非常量的也可以是常量的。但是要注意无论什么情况都不能使用常量引用修改其引用的变量的值。