特别
while一般而言,所有非零值都视为真,只有0被视为假。
#include <iostream>
using namespace std;
int main(void)
{
printf("%d\n", 1);
int i = -6;
// while 一般而言,所有非零值都视为真,只有0被视为假
while (i)
{
printf("%d\n", i);
i++;
}
return 0;
}指针与const
指针在初始化时,引用了,其它变量的值,无论对指针的地址还是对指针值
+ const。修改变量的值,都将影响到指针
- 对
*后面加入const 代表将地址设置为常量,地址不可变,但是对应的值可以改变。 - 第
*前面的值加const,对应的值*p不能改变,但是可以改变p的地址,通过此形式改变了*p对应的值。 - 对
*的前后都添加了const,代表对应的地址,和值都不能改变,但是如果在const初始化时是引用其它变量的值,就可以修改其它变量的值,来间接修改此值。
/*
关于const与指针之间的运用问题
*/
#include <iostream>
using namespace std;
int main(void)
{
int a = 6;
int i = 1;
// *p常量化
const int* p = &a;
cout << "a: " << *p <<endl; //6
p = &i;
cout << "p = &i : " << *p << endl; //1
//*p = 10; //*p为const值不可改变
cout << "*p: " << *p << endl; //
// 对a的值进行修改,间接的修改*p的值
a = 7;
p = &a;
// 通过对a值的修改,间接修改了 指向p地址的p
cout << "*p: " << *p << endl; // 7
int b = 8;
//*p固定值不能改变,但是p的地址可以改变
p = &b; //通过赋值新的地址p
cout << "*p: " << *p << endl;
// t地址常量
int* const T = &a;
cout << "const p: " << *T << endl; //值为7
// T = &b; //地址为cosnt常量,不可进行修改
//当忍让可以通过修改a的值,间接修改引了a地址的T
a = 9;
cout << "const p: " << *T << endl;
// 地址和值都是常量
const int* const S = &a; //初始化为a的9值
// S = &b; //地址值不再允许改变
// 通过a的值可以 改变S的值
//
a = 10; //a仍然为变量,仍然可以进行改变
cout << "const int* const S :" << *S << endl;
//对*S以及S的地址,在初始化后不可再次改变
return 0;
}数组a[]中a与&a区别
值相同a指的是a[0]的地址&a指的是数组a的地址- 数组名代表数组第一个元素的地址,
&数组名代表整个数组的地址,从而导致a+1和&a+1有本质的区别
char* 与char a[]
char *a = "abcd"char a[20] = "abcd"
- 读写能力
字符串数据存放在
常量存储区,通过指针只可以访问字符串常量,而不可以改变它
数组数据存放在栈,可以通过指针去访问和修改数组内容
- 赋值时刻
指针编译时就已经确认了,因为是
常量
数组运行时确认
- 存取效率
存于
常量存储区,在栈上的数组比指针所指向字符串快
数组存放在栈上,因此块
strlen不计\0,但是sizeof计算字符串容量时算\0,占两个字节。
读取位置⛵
// 不加*代表真个字符串地址,加*对应地址的单个 字符
const char* a = "helloworld"; //常量字符串
//在没有取单独值时,就是指针移动,指针移动的是对应的字符对应的字节
cout << a + 1 << endl; //起始地址右移,变为elloworld
char b[] = "morning";
cout << b+1 << endl; //同样地址右移,变为orning
//其相等,取地址位置的一个字符
cout << *(a + 1) << endl; //取固定值
cout << b[1] << endl;;
printf("%c\n", *(a + 1));
printf("%c\n", b[1]);为char*申请固定空间
char*代表字符串指针,单个,为其申请空间,要取其字符串指针的地址即二级指针进行空间申请。使用二级指针渠道传入参数n的真实地址,而不是局部变量,局部变量在栈中函数结束将被释放,申请空间会无效。要使用二级指针,指向字符串n的地址。
void getMemory(char** n)
{
*n = (char*)malloc(100);
}
char* n = NULL;
getMemory(&n);
strcpy(n, "nihaohaohao");
cout << n << endl;整型在内存中的存储及运算规则
有符号
二进制表示正反的方式,在首位
1为负数0为正数数据以
补码的形式保存在内存中。
正数的反码和补码是其本身在类型转换的过程中直接
保存低位即可在
int转char型,-2对应的补码1111 1110转为4位,直接截断得到四位,即1110,这个数对应的还是-2;在还原时:
-1,再求反码即得原码得到原数
char转int,若高位是0,正数,高位补0,若为负数高位补1即可
截断
当将不同类型元素混合赋值且指向内存空间大小不一样时,就会
发生截断。截断会高位截断,保留低位数据,当-1整型存入字符串数据中,就会发生截断
整型提升
整型提升的意义在于:表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度。通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算。
int main()
{
char a = -1; //-1截断后存储到a中
//10000000000000000000000000000001 -1的原码
//11111111111111111111111111111110 -1的反码
//11111111111111111111111111111111 -1的补码
//11111111 - a 截断后char a中a所存的补码
signed char b = -1;
//11111111111111111111111111111111 -1的补码
//11111111 - b b的补码
//
unsigned char c = -1;
//11111111111111111111111111111111 -1的补码
//11111111 - c c的补码。
//
//整型提升
printf("a=%d,b=%d,c=%d", a, b, c);
//-1 -1
//11111111111111111111111111111111
//11111111111111111111111111111110
//10000000000000000000000000000001
//11111111
//00000000000000000000000011111111
return 0;
}八道笔试题集合
指针层级
过深时,通过画关系的形式表达出来。
sizeof小练
牢记:sizeof的计算在编译时刻,把它当
常量表达式使用,且会忽略掉表达式内部的各种运算,指针在32位系统中占4个字节,在64位系统中占8个字节
sizeof计算字符串容量时算\0与此同时:sizeof("\0")=2;- 在
编译阶段处理,sizeof作用范围内的内容不能被编译,所以sizeof()内的运算不被执行 sizeof(函数)=sizeof(返回值类型)- 联合体:
最长成员的大小对齐 sizeof(2.5+3.14)实际上是sizeof(double)切记需要识别出其类型sizeof可以对函数调用求值,实际上是对返回值类型求值
int func(char s[5])
{
cout << endl;
return 1;
}
sizeof(func("1234")); //得出返回值类型int的大小,4个字节sizeof不可用
不能对函数名求值不能对不确定返回值的类型求值,如void
#include <stdio.h>
int main(void)
{
short num = 20;
int a = 1;
printf("%d\n", sizeof(num = a+5));
printf("%d\n", num);
return 0;
}笔试1
#include<stdio.h>
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
//a为数组a[0]的地址与数组a地址重合,&a取的就是数组a的地址
int* ptr = (int*)(&a + 1); // 取了数组a之后的地址空间
printf("%d,%d", *(a + 1), *(ptr - 1)); // a的地址空间减去一个sizeof(int) 得出结果: 2,5
return 0;
}
指针的类型决定了指针+1时的步长,指针的类型决定了对指针进行解引用操作时,访问的空间大小
笔试2
指针移动,移动对应类型的
sizeof(类型)的字节数,注意转换关系,要根据转换关系灵活应用
#include<stdio.h>
//此结构体的大小是20个字节
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
int main()
{
p = (struct Test*)0x100000;//假设p的值为0x100000。 //p的地址0x0000000000100000
//%p输出地址
//p为结构体类型,每次指针移动一位,就是移动的strct Test的大小,和数组移动时一样
// 移动了一位,就是内存地址移动了20个字节
printf("%p\n", p + 0x1); //0x100020
// 使用了类型转换,无符号长整型 对应的是值 +1
printf("%p\n", (unsigned long)p + 0x1); //0x100001
// 使用无符号整型,那整型+1就是int,对应的是指针类型,要加4个字节就是4个字节
printf("%p\n", (unsigned int*)p + 0x1); //0x100004
return 0;
}笔试3
#include<stdio.h>
int main()
{
int a[4] = { 1, 2, 3, 4 };
int* ptr1 = (int*)(&a + 1); //上通4 &a取的是整个数组a的地址,+1即跳过一个int(*)[4]类型,然后再将它强制转换为int *类型
// 首先计算出a在内存中的存储,使用小端存储结构,+1之后
int* ptr2 = (int*)((int)a + 1);
printf("%x,%x", ptr1[-1], *ptr2); //%x以16进制打印
return 0;
}笔试4
逗号表达式
逗号表达式的运算过程为:从左往右逐个计算表达式- 逗号表达式作为一个
整体,它的值为最后一个表达式(也即表达式n)的值 逗号运算符的优先级别在所有运算符中最低
main() { int x,y,z; x=1; y=1; //由于后面没有括号,且逗号的优先级是最低的,z就等于x++了,后面照样运行 z=x++,y++,++y; printf("%d,%d,%d",x,y,x); }
#include<stdio.h>
int main()
{
// (0, 1) 逗号运算符,取最后一个
// { {1,3},{5,0},{0,0} }
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int* p;
p = a[0];
printf("%d", p[0]); //1
return 0;
}笔试5
#include<stdio.h>
int main()
{
int a[5][5];
// p是一个数组指针,指向一个有4个整型元素的数组
int(*p)[4]; // 取对应的内存,指针画笔
// a是数组名,数组名代表的是数组首元素的地址,二维数组的首元素是第一行元素,
p = a;
//-4取地址,以补码16进制的形式
printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}笔试6
#include<stdio.h>
int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int* ptr1 = (int*)(&aa + 1); //取了数组aa之后的内存
int* ptr2 = (int*)(*(aa + 1)); // 取的是aa[1][0]的地址
printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1)); //10,5
return 0;
}笔试7
#include<stdio.h>
int main()
{
// 代表多个字符串a[0],a[1],a[2] char变成了字符串
const char* a[] = { "work","at","alibaba" };
// a的地址默认是a[0]的地址,
const char** pa = a;
pa++; //a[1]
printf("%s\n", *pa); //at
return 0;
}笔试8
#include <stdio.h>
int main()
{
char* c[] = { "ENTER","NEW","POINT","FIRST" };
char** cp[] = { c + 3,c + 2,c + 1,c };
char*** cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *-- * ++cpp + 3);
printf("%s\n", *cpp[-2] + 3);
printf("%s\n", cpp[-1][-1] + 1);
return 0;
}