1.下面程序的输出结果为多少(32为机器上)
void Func(char str_arg[2])
{
int m = sizeof(str_arg);
int n = strlen(str_arg);
printf("%d\n", m);//4
printf("%d\n", n);//5
}
int main(void)
{
char str[] = "Hello";
Func(str);
system("pause");
return 0;
}
sizeof和strlen()都可以用来统计字符串所占用的大小,二者的区别为:
- sizeof是运算符,而strlen是函数;
- strlen必须以char *作为参数,且必须以'\0'结尾;而sizeof()可以用于其他类型;
- strlen统计字符串中字符的长度,不包括结尾的'\0';
- 数组做sizeof的参数不退化,而传递给strlen就变为指针
sizeof(str):占用的字节为5 + 1 = 6,其中1为末尾的'\0';
strlen(str):5
当数组作为函数的参数时,其自动转换为指向函数的指针,sizeof(str_arg)表示的是指针的长度,在32为计算机上为4位。
Func(str):传递的是指针,大小为4
2. 1<<3+2 的值是 32
+的优先级高于<<
所以是1<<5 左移位5位,00001------>10000,也就是2^5=32,左移在不溢出的情况下相当于乘以2
优先级记忆方法如下:
记住一个最高的:构造类型的元素或成员以及小括号。
记住一个最低的:逗号运算符。
剩余的是一、二、三、赋值。
意思是单目、双目、三目和赋值运算符。
在诸多运算符中,又分为:
算术、关系、逻辑。
两种位操作运算符中,移位运算符在算术运算符后边,逻辑位运算符在逻辑运算符的前面。再细分如下:
算术运算符分 *,/,%高于+,-。
关系运算符中,〉,〉=,<,<=高于==,!=。
逻辑运算符中,除了逻辑求反(!)是单目外,逻辑与(&&)高于逻辑或(||)。
逻辑位运算符中,除了逻辑按位求反(~)外,按位与(&)高于按位半加(^),高于按位或(|)。
这样就将15种优先级都记住了,再将记忆方法总结如下:
去掉一个最高的,去掉一个最低的,剩下的是一、二、三、赋值。双目运算符中,顺序为算术、关系和逻辑,移位和逻辑位插入其中。
3. 在小端序的机器中,如果
union X
{
int x;
char y[4];
}a;
int main()
{
a.x = 0X11223344;
printf("%x\n", a.y[0]);//44
printf("%x\n", a.y[1]);//33
printf("%x\n", a.y[2]);//22
printf("%x\n", a.y[3]);//11
system("pause");
return 0;
}
大端模式(Big_endian):字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中。
小端模式(Little_endian):字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中。
一个很好的记忆方法 大序端按照顺序写 小序端倒序写
union 型数据所占的空间等于其最大的成员所占的空间。对union型的成员的存取都是相对于该联合体基地址的偏移量为0 处开始,也就是联合体的访问不论对哪个变量的存取都是从union 的首地址位置开始。
union 维护足够的空间来置放多个数据成员中的“一种”,而不是为每一个数据成员配置空间,在union 中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的起始地址。例子如下:
union StateMachine
{
char character;
int number;
char *str;
double exp;
};
一个union 只配置一个足够大的空间以来容纳最大长度的数据成员,以上例而言,最大长度是double 型态,所以StateMachine 的空间大小就是double 数据类型的大小。
4.阅读如下代码,请问:p和“hello ,world”存储在内存 栈,只读存储区
const char *p="hello,world";
局部变量存放在栈中,堆中存放的是new和malloc开辟出的,而程序中定义的常量存放在只读存储区
局部变量:栈
全局变量,static变量:全局静态区域
动态变量:堆
局栈动堆
5. 空指针是指 所指向的空间位置就是地址0的指针
我们判断空指针用 if(ptr==NULL) 来判断 , 而NULL在宏定义中定义为0 ,所以判断空指针就是判断地址是否为0
空指针:在VS里是为NULL的指针,在C/C++中,NULL=0
A.未存放任何数据的指针,说法没有所指向的空间位置就是地址0的指针完善,事实上,指向的地方可以是一个地址,只是那个地址不一定有数据
B.所指向的空间位置存放着数据0的指针肯定错,int a = 0, int *b = &a
C.所指向的空间位置可用于存放任何类型数据的指针 void *也是指针,且可以强制类型转换,指针的大小与机器字长有关.
6.如下代码结果是 a=2,x=1
int main()
{
int a, x;
for (a = 0, x = 0; a <= 1 && !x++; a++)
{
a++;
}
printf("%d %d", a, x);// 2 1
system("pause");
return 0;
}
此题关键在于第二个判断条件: !x++。!与后置++同时出现时,后置++优先级高于!,所以!x++相当于!(x++),但是后置自增运算符是等语句执行完成之后再自增。
7.写一个宏,输入两个参数,返回较小的一个:#define Min(X,Y) ((X)>=(Y)?(Y):(X))//结尾没有';'
8. 下面程序输出结果为 5 ,2000000,3
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *p1 = (int*)(&a + 1);//&(a+1)指的是下一个数组的首地址,也就是下一行首地址
int *p2 = (int*)((int)a + 1);
int *p3 = (int*)(a + 1);
printf("%d ,%x,%d\n", p1[-1], p2[0], p3[1]);//5 ,2000000,3
system("pause");
return 0;
}
&a + 1: 取数组a 的首地址,该地址的值加上sizeof(a) 的值,即&a + 5*sizeof(int),也就是下一个数组的首地址,显然当前指针已经越过了数组的界限。
(int *)(&a+1): 则是把上一步计算出来的地址,强制转换为int * 类型。
*(a+1): a,&a 的值是一样的,但意思不一样,a 是数组首元素的首地址,也就是a[0]的首地址,a+1 是数组下一元素的首地址,即a[1]的首地址。&a 是数组的首地址,,&a+1 是下一个数组的首地址。
a+1 就是指针向后偏移一个元素,指向2,p3[1]~*(p3+1),即就是3.
(int)a,已经把a的地址强转成int型数字(32bit),所以“((int)a+1); ”实际指向了整个数组内存块的第二个地址。