定义的是指针变量,存放的是地址这个值
int* fun()
{
int ar[10] = { 12,23,34,45,56,67,78,89,90,100 };
//如果数组开辟空间很大,可正常打印
//没有对原来的数据进行覆盖
int* p = ar;
return p;
}
int main()
{
int* p = fun();
//调用完之后,将空间还给栈,此时指针已失效,没有所指的空间
for (int i = 0; i < 10; ++i)
{
printf("%d\n", p[i]);
}
printf("\n");
}
int main()
{
int a = 0x12345678;
int* ip = &a;
char* cp = (char*)&a;
char* p = (char*)&a;
*p = 'a';
p = p + 1;
*p = 'b';
p = p + 1;
*p = 'c';
p = p + 1;
*p == 'd';
return 0;
}
X86—小端存放
指针+1和自身类型有关,与所指之物无关
首地址从低地址开始
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6WwWiXiF-1627967914588)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20210802180007082.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZP1Sy8U9-1627967914591)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20210802180717411.png)]
int main()
{
sizeof(ar);//elem num,elem type
//其他情况下均为数组首元素的地址
int* ip = ar;//&ar[0]
&ar;//数组的地址
int(*s)[5] = &ar;
//s开辟出4个字节,s:一个指针空间
int* pa[5];
return 0;
}
s=&ar;//数组的地址
ip=ar;//数组首元素的地址
大小相同,类型不同(指针+1的能力不同)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uojzoqoy-1627967914594)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20210802181737931.png)]
同类型指针相减,减后的结果是此类型的元素个数,不是字节个数
void
函数不需要返回值时,void fun(a)
函数不允许接受参数时,int fun(void)
限定运算操作,不允许参与运行
断言不参与任何运算,把值强转为无类型
assert(dest != nullptr && src != nullptr);//right
assert(dest != nullptr) && (src != nullptr);//error
void
不可以定义变量,但可以定义指针变量
void指针可以指向任意类型变量的地址
char ch = 'a';
int x = 10;
double dx = 12.23;
void* vp = &ch;
vp = &x;
vp = &dx;
int main()
{
const int n = 5;
int ar[n] = { 12,23,34,45,56 };
void* vp = ar;
vp = &ar;
int a = 10;
int* ip = &a;
vp = &ip;
vp = &vp;
sizeof(vp);//可以确定指针的大小,不能确定所指之物的大小
sizeof(*vp);//error,不知道它是什么类型
}
GUN中允许,void* 和 char* 等价
不同的标准,无类型有不同的规范
函数的形参为 void* 指针变量时,函数就可以接受任意类型变量的地址
void my_memset(void* src, unsigned char val, size_t count)
{
assert(src != nullptr);
char* cp = (char*)src;
for (int i = 0; i < count; ++i)
{
*cp = val;
cp = cp + 1;
}
}
int main()
{
const int n = 5;
int ar[n];
char cr[n];
double dr[n];
my_memset(ar, 0, sizeof(int) * n);//字节个数
my_memset(cr, 0, sizeof(char) * n);
my_memset(dr, 0, sizeof(double) * n);
}
//my_memset 内存拷贝
//count字节个数
void my_memcpy(void* dest, const void* src, size_t count)
//使用 void* 类型,提高其通用性
{
assert(dest != nullptr && src != nullptr);
char* darg = (char*)dest;
const char* sarg = (const char*)src;
//忽略类型,全部以字节形式表示
for (int i = 0; i < count; ++i)
{
*darg++ = *sarg++;
}
}
int main()
{
const int n = 5;
int ar1[n] = { 12,23,34,45,56 };
int ar2[n];
double dr1[n] = { 1.2,2.3,3.4,4.5,5.6 };
double dr2[n];
my_memcpy(ar2, ar1, sizeof(int) * n);
my_memcpy(dr2, dr1, sizeof(double) * n);
return 0;
}
将字符串库里面的函数编译运行出来,调用是基础操作,必须得知道库函数是如何实现的
小厂:strlen strcmp strcat strcpy
大厂:memmove(为什么把形参设计成无类型指针,其好处是什么?)
函数内部,无类型指针无法对内存进行解析,所以要对它进行强转
atoi—很重要
int my_strcmp(const char* ap, const char* bp)
{
assert(ap != nullptr && bp != nullptr);
while (*ap != '\0' && *bp != '\0' && *ap == *bp)
{
ap++;
bp++;
}
return (*ap - *bp);
}
int my_strcmp(const char* ap, const char* bp)
{
assert(ap != nullptr && bp != nullptr);
int k = 0;
while ((k = *ap - *bp) == 0 && *ap++ &&* bp++);
return k;
}