一、指针强转介绍
指针强转:实现指针变量类型的统一,归一化指针加一的偏移量。
int arr[] = {1, 2, 3};
int* p = arr;
// int == long <= long long
long long *L = (long long*)p;
printf("%lld ", *L); # 每次偏移八个字节
// 指针自增相当于 p = p + sizeof(指针变量类型)*1;
p++;
// 值得注意的是:指针加一与指针自增效果截然不同,加一仅为4字节,自增为指针自身的 Size。
p = p + 1;
二、知识点
1.内存开辟区别
注意点:Wins端为小端存储模式,即对于单个变量(低字节存于低位,高字节存于高位)
- 栈内存开辟:从高地址向低地址进行内存开辟。
PS: 每个变量开辟内存时,会有上下各四字节的边界变量。 - 数组内存开辟:从低地址向高地址进行数据存储。
2.一级指针与二级指针
二级指针(一级指针地址) --》 一级指针(变量地址) --》变量(数值)
int a = 10;
int* p = &a;
int** pp = &p;
/*
**pp == a;
*pp == p == &a;
pp == &p;
-----------
p = &a;
*p = a;
*/
3.Const与指针
3.1 Const 与一级指针
主要观察const与指针星号的关系:
const*p 限制域为 *p (指针所指的数值)
*const p 限制域为 p(指针变量)
三种形式:
- int* const p;
- const int* p;
- int const* p;
int a = 0;
int b = 0;
const int* p = &a;// 限制域为 *p
*p = 10;// 触及限制域*p,指向内容不可修改
p = &b; // true
int* const q = &a; // 限制域为 p
*q = 10; // true
q = &b; // 触及限制域p,一级指针地址不可更改
const int*const r = &a; // 限制域为 *p,p
*r = 10; // Error
r = &b; // Error
const int a=0;
const int b=0;
//该语句若无const则语句错误,若正确,则代表可以通过指针改变a的值,所以语句应加上const来确保a的值不会改变
const int *p=&a;
3.2 Const 与二级指针
相比于一级指针,二级指针有更多的组合,即需要注意限制域之间的联系。
int a = 0; int b = 0;
const int *p = &a; // 限制域:*p
int *const q = &a; // 限制域:*p,q
int **s1 = &p;
s1 = &q; // 修改二级指针,未触发限制域
**s1 = 20; // 触发限制域 *p, **s1(*&p) == *p(*&a) == a
const int **t1 = &p; // 限制域:**t1
*t1 = &b; // 修改 *t1,未触发限制域
**t1 = 10; //Error,触发限制域 **t1
int * const* s2 = &p; //二级指针s2指向一级指针p的地址,设置限制域:*s2 == p,即不允许修改二级指针的“内容”
*s2 = &a; //Error,触发限制域 *s2
**s2 = 100; //True
课堂练习
const int a = 0; // 设置常变量
int b = 0;
const int *p = &a; // 常变量对应的指针应为常指针,限制域:*p
p = &b; // True
*p = 10; // Error,触发限制域*p
const int *const *s = &p; // 限制域:**s(*&p),*s(p, *&a)
*s = &a; //Error,触发限制域*s
**s = 10; //Error,触发限制域**s
const int ** t = &p; // 限制域:**t(*&p)
**t = 10 //Error,触发限制域**s
p = &a; // True
*t = &a; // True
作业练习
作业一
用指针加 const 限制实现 strlen,strcmp(const charstr,const charsrc), strcat, strcpy函数
// 实现 strlen,strcmp(const char*str,const char*src), strcat, strcpy函数
// Strcmp函数
int str_cmp(const char* str1, const char* str2) {
assert(str1 != NULL && str2 != NULL);
while (*str1 == *str2)
{
if (*str1 == '\0') {
return 0;
}
str1++;
str2++;
}
return *str1 - *str2;
// Strlen函数
int str_len(const char* str1) {
int count = 0;
while (*str1 != '\0') {
count++;
str1++;
}
return count;
}
// Strcpy函数
int str_cpy(char* str, const char* str1, int len) {
int output = (len > (strlen(str1) + 1));
int str1_len_temp = str_len(str1);
if (output > 0) {
for (int i = 0; i < str1_len_temp; i++) {
*(str + i) = *(str1 + i);
}
output = 1;
}
return output;
}
// Strcat函数
int str_cat(const char* str1, const char* str2, char* str, int len) {
int output = (len > (strlen(str1) + strlen(str2) + 1));
if (output > 0) {
str_cpy(str, str1, len);
str_cpy(str + str_len(str1), str2, len);
output = 1;
}
return output;
}
int main(){
char str1[] = "Hello";
char str2[] = "Hey";
const int strs_len = 20;
// 切记按照标准,初始化,否则str_cpy时会出现拷贝字符不统一。
char strs[strs_len] = "0";
int cpy_temp = str_cpy(str1, strs, strs_len);
int cat_temp = str_cat(str1, str2, strs, strs_len);
int output = str_cmp(str1, str2);
int str_lens = str_len(str1);
return 0;
}
作业二
实现:atoi (必须) itoa函数 (思考)
// 实现:atoi (必须) itoa函数 (思考)
int my_atoi(char* pstr) {
assert(pstr != NULL);
int num = 0;
bool flag = false; // 标记正负号
// 跳过空格区
while (*pstr == ' ')
{
pstr++;
}
// 正负号处理
if (*pstr == '-' || *pstr == '+') {
if (*pstr == '+') {
flag = true;
}
pstr++;
}
// 判断数字,并将字符串转换为数字
while (*pstr >= '0' && *pstr <= '9')
{
num = num * 10 + (*pstr) - '0';
pstr++;
}
// 添加正负号
num = num * (flag ? 1 : 0);
return num;
}
总结
今天主要讲了指针的强转, Const与指针之间的关系(注意二级指针的调用关系)。