Summer 10

1.关于以下代码,正确的说法是

    char acX[] = "abc";
    char acY[] = { 'a', 'b', 'c' };
    char *szX = "abc";
    char *szY = "abc";
A acX和acY都是数组,当然可以修改

B 因为"abc"是常量字符串,当它被多次使用时,编译器并不愿意再多分配出额外的内存空间存放多个"abc",而是重复使用这一个"abc",所以,scX和scY指针会指向同一个地址。

C 因为acX是字符串数组,字符串的尾部有一个结束符'\0',所以acX有四个元素,内存空间比acY大

D 字符指针指向的是常量字符串,常量字符串不能修改.

2.运行以下C语言代码,输出的结果是 stra     tra      ra

int main()
{
	char *str[3] = { "stra", "strb", "strc" };
	char *p = str[0];
	int i = 0;
	while (i<3)
	{
		printf("%s\n", p++);//stra     tra      ra
		i++;
	}
	system("pause");
	return 0;
}

创建了一个指针数组str,它的每个数组元素相当于一个指针变量,也就是说str数组中每个元素存放的是字符串的地址。str[0]存放的是第一个字符串的地址,赋值给p,p是一个指向char型元素的指针,printf输出遇到空字符停止

a,p是char*类型,每次++,后移一位(char)

b,char *p=str[0]相当于char *p="stra",p先指向s,p++后,指向t

c,printf输出遇到空字符停止

3.设 int x[] = { 1, 2, 3, 4, 5, 6 },*p=x; 则值为3的表达式是   p += 2; *p++;

    int x[] = { 1, 2, 3, 4, 5, 6 },*p=x;
	p += 2;
	printf("%d\n", *p++);

4. 以下关于指针的说法,正确的是 (C)

A. int *const p与int const *p等价

B. const int *p与int *const p等价

C. const int *p与int const *p等价

D. int *p[10]与int (*p)[10]等价


int *const p是指向整数数据的常量指针,指针不可再被修改。

int const *p 是指向数据类型为常量的指针p,p所指向的数据值不可更改。 

const int *p与int const *p等价    

int *p[10]与int (*p)[10]不等价    前者是一个数组,数组里存放十个这样的指向整形数据的指针,后者是一个数组指针,p指向存放整形数据的数组

最简单的方法,把int去掉,从右往左看 ,直接看const在*的那一侧,同一侧就是等价,不同侧就不等价。

4. 如下代码输出结果 未知

char *myString()
{
	char buffer[6] = { 0 };
	char *s = "Hello World!";
	for (int i = 0; i < sizeof(buffer)-1; i++)
	{
		buffer[i] = *(s + i);
	}
	//printf("%d\n", sizeof(buffer));6
	return buffer;
}

int main()
{
	printf("%s\n", myString());
	system("pause");
	return 0;
}

函数char *myString()中没有使用new或者malloc分配内存,所有buffer数组的内存区域在栈区随着char *myString()的结束,栈区内存释放,字符数组也就不存在了,所以会产生野指针,输出结果未知 。


局部数组,具有局部作用域,当函数调用结束之后,数组也就被操作系统销毁了,即回收了他的内存空间,它里面的东西随时都有可能被覆盖。虽然此时我们获得了指向这一块内存的指针,但此刻里面的东西很大可能都不是我们想要的了。
a: 返回一个静态的数组
b: 动态分配内存
c: 使用全局数组

5.下面的代码输出 4,1

int main()
{
	int i = 1;
	printf("%d,%d\n", sizeof(i++), i);//4,1
	system("pause");
	return 0;
}

i++还是int类型,跟数据是多少没有关系,所以最后结果为4(int无论在32位还是64位都是占4字节)。如果sizeof的操作数是一个表达式的话,这个表达式时不会被计算的。 
sizeof当预处理看就行了,它后面括号里的东西,根本不求值,只根据C的一堆规则判断结果类型,然后返回结果类型的大小。另外一个操作符typeid也是如此。

6.下面代码输出 255

int main()
{
	char a[1000];
	int i;
	for (i = 0; i < 1000; i++)
	{
		a[i] = (char)(-1 - i);
	}
	printf("%d\n", strlen(a));//255
	system("pause");
	return 0;
}

-128
原 1000 0000, 0000 0000, 0000 0000, 1000 0000
反 1111 1111, 1111 1111, 1111 1111, 0111 1111
补 1111 1111, 1111 1111, 1111 1111, 1000 0000

-129
原 1000 0000, 0000 0000, 0000 0000, 1000 0001
反 1111 1111, 1111 1111, 1111 1111, 0111 1110
补 1111 1111, 1111 1111, 1111 1111, 0111 1111

-255
原 1000 0000, 0000 0000, 0000 0000, 1111 1111
反 1111 1111, 1111 1111, 1111 1111, 0000 0000
补 1111 1111, 1111 1111, 1111 1111, 0000 0001

-256
原 1000 0000, 0000 0000, 0000 0001, 0000 0000
反 1111 1111, 1111 1111, 1111 1110, 1111 1111
补 1111 1111, 1111 1111, 1111 1111, 0000 0000
for 循环内,当i 的值为0 时,a[0]的值为-1。关键就是-1 在内存里面如何存储。
    我们知道在计算机系统中,数值一律用补码来表示(存储)。主要原因是使用补码,可以将符号位和其它位统一处理;同时,减法也可按加法来处理。另外,两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。正数的补码与其原码一致;负数的补码:符号位为1,其余位为该数绝对值的原码按位取反,然后整个数加1。
    按照负数补码的规则,可以知道-1 的补码为0xff,-2 的补码为0xfe……当i 的值为127时,a[127]的值为-128,而-128 是char 类型数据能表示的最小的负数。当i 继续增加,a[128]的值肯定不能是-129。因为这时候发生了溢出,-129 需要9 位才能存储下来,而char 类型
数据只有8 位,所以最高位被丢弃。剩下的8 位是原来9 位补码的低8 位的值,即0x7f。当i 继续增加到255 的时候,-256 的补码的低8 位为0。然后当i 增加到256 时,-257 的补码的低8 位全为1,即低八位的补码为0xff,如此又开始一轮新的循环……
    按照上面的分析,a[0]到a[254]里面的值都不为0,而a[255]的值为0。strlen 函数是计算字符串长度的,并不包含字符串最后的‘\0 ’。而判断一个字符串是否结束的标志就是看是否遇到‘\0 ’。如果遇到‘\0 ’,则认为本字符串结束。
    分析到这里,strlen(a)的值为255 应该完全能理解了。这个问题的关键就是要明白char类型默认情况下是有符号的,其表示的值的范围为[-128,127],超出这个范围的值会产生溢出。另外还要清楚的就是负数的补码怎么表示。弄明白了这两点,这个问题其实就很简单了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值