C语言代码考评示例
#include<stdio.h>
typedef struct info1
{
char *next;
}INFO1;
typedef struct info
{
short *next;
}INFO2;
typedef struct info3
{
int *next;
}INFO3;
typedef struct info4
{
double *next;
}INFO4;
int main(int argc ,char* argv[])
{
printf("%d\n",sizeof(INFO1));
printf("%d\n",sizeof(INFO2));
printf("%d\n",sizeof(INFO3));
printf("%d\n",sizeof(INFO4));
return 0;
}
你能否得到上述输出结果的原因,试阐述之!
32位机为指针分配4个字节,每个字节8位
理论上64位机为指针分配8个字节,每个字节8位,若测试的结果不对应,这可能和编译器有关。一般的编译器都是32位的编译器!所以对编译器分配的空间要视电脑的操作系统和编译器而定。
(2)#include<stdio.h>
int main(int argc,char *argv[])
{
char *p="hello world\n";
printf("%d\n",sizeof(p));
printf("%d\n",sizeof(*p));
int a[10];
int *b;
b=&a;
printf("%d\n",sizeof(b));
printf("%d\n",sizeof(*b));
getch();
}
请结合第(1)例子,说明该例输出结果的原理。
printf("%d\n",sizeof(p));指向的是一个指针,32位编译器为指针分配4个字节
printf("%d\n",sizeof(*p));指向的指针的首地址,它是一个字符,所以测试结果是1。大家要理解指针的指向问题:一个是指针有指向时,一个是指针无指针时。
(3)
#include<stdio.h>
typedef struct info
{
char ch1;
char ch2;
int data;
double index;
char extra;
}INFO;
int main(int argc,char argv[])
{
printf("%d\n",sizeof(INFO));
printf("%d\n",sizeof(double));
getch();
return 0;
}
你能否不运行代码而说出该程序运行结果?能否分析出其原理?并总结出计算结构体大小的一般运算方法?
在32位机里,编译器为char分配1个字节,但是此结构体里还有其他类型的数据项,int和double,为了对齐,要为char补上3个字节,其他的就不需要补内存空间了。
我认为测结构体的大小时,需要找到一个基础类型数据!然后若发现和其基础类型数据小的,要补够它的基础字节,使其和基础字节的字节数相同!关键是寻找基础字节。
(4)
#include<stdio.h>
typedef struct info
{
char ch1;
char ch2;
int data;
double index;
char extra;
}INFO;
#define OFFSET (size_t)&(((INFO*)0)->extra)
int main(int argc, char *argv[])
{
printf("%d\n",OFFSET);
printf("%d\n",(size_t)&(((INFO*)0)->extra));
printf("%d\n",(size_t)&(((INFO*)1)->extra));
printf("%d\n",(size_t)&(((INFO*)3)->extra));
return 0;
}
结合例子(3),描述宏OFFSET的功能!
这个题首先要理解size_t
它是一种“整型”类型,里面保存的是一个整数,就像int, long那样。这种整数用来记录一个大小(size)。size_t的全称应该是size type,就是说“一种用来记录大小的数据类型”。通常我们用sizeof(XXX)操作,这个操作所得到的结果就是size_t类型。因为size_t类型的数据其实是保存了一个整数,所以它也可以做加减乘除,也可以转化为int并赋值给int类型的变量。经测试发现,在32位系统中size_t是4字节的,而在64位系统中,size_t是8字节的。
类似的还有wchar_t, ptrdiff_t。wchar_t就是wide char type,“一种用来记录一个宽字符的数据类型”。ptrdiff_t就是pointer difference type,“一种用来记录两个指针之间的距离的数据类型”。
再理解&运算符
按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。
例如:9&5可写算式如下: 00001001 (9的二进制补码)&00000101 (5的二进制补码) 00000001 (1的二进制补码)可见9&5=1。
(((INFO*)0)->extra)
按我的理解就是一个INFO类型的指针,指向extea,得到一个数据;
Size_t得到一个结果,是一个类似int形的数据,(((INFO*)0)->extra)得到一个数据,两者进行与运算,发现在在二进制的反码在从右到左的第五位相同,所以结果为16.
(5)
#include<stdio.h>
#define SWAP(x,y)\
{ \
int t=x;\
x=y; \
y=t; \
};\
int main(int argc,char *argv[])
{
int a=20,b=15;
SWAP(a,b);
printf("a=%d,b=%d\n",a,b);
return 0;
}
该段代码能正常运行吗?如果能运行,请分析输出结果,如果不能,请指出其错误,并修改之!使其完成a、b变量数值的交换!
这是一个交换函数,运行之后发现它实现了a与b的交换,没有定义指针变量。
在宏的末尾不需要分号,在这里用到了链接符,所以就无所谓要不要了。这让我想起了定义函数实现两个数的交换,宏不需要指针,而函数交换则需要指针。
(6)
#include<stdio.h>
int main(int argc,char *argv[])
{
int a[5]={1,2,3,4,5};
int* ptr=(int *)(&a+1);
printf("%d,%d\n",*(a+1),*(ptr-1));
return 0;
}
请写出该段代码的结果,并理解该结果产生的原因!
int *ptr=(int *)(&a+1) 是指向数组a的毗邻区,ptr-1是ptr指向毗邻区之后又往后移动了一个位置,所以指向a[4],即*(ptr-1)的结果为5。
(a+1指向的是数组a的首地址的下一个地址,所以*(a+1)的结果是2。
(7)
#include<stdio.h>
void foo(int b[][3]);
int main()
{
int a[3][3]={{1,2,3,},{4,5,6},{7,8,9}};
foo(a);
printf("%d\n",a[2][1]);
return 0;
}
void foo(int a[][3])
{
++a;
a[1][1]=9;
}
请写出代码的输出结果!
刚开始传入数组a的首地址,然后数组a的地址自加一,指向a[1][1],从他以后的数组又看做一个新数组,原数组a[1][1]相当于新数组的a[0][0],此时a[1][1]相当于原数组的a[2][1]被赋值为9原先的7被覆盖,返回main函数,输出a[2][1]所以为9了。
(8)
#include<stdio.h>
#define ADD(a,b) (a*b)
int main()
{
printf("%d\n",ADD(3+5,6+2));
return 0;
}
请写出输出结果,并总结该宏的特点是什么?
宏替换有一条重要的原则就是“后替前”,在这里进行替换后是“3+5*6+2”,它在计算时仍按+-*/运算的一般规则进行运算,先计算5*6=30,然后再和3、2相加,所以结果为35。而不是把(3+5)整体看做a,(6+2)整体看做b。宏替换我觉得就是将替换的照抄,计算时仍按一般的运算规则进行计算。
(9)
void test1()
{
char *s;
s="hello world";
printf("%s\n",s);
}
void test2()
{
int a=2;
int *p;
p=&a;
printf("%d\n",*p);
}
void test3()
{
int *p=2;
printf("%d\n",*p);
}
void test4()
{
int *p=(int *)malloc(sizeof(int));
*p=2;
printf("%d\n",*p);
free(p);
}
上述函数哪一个是错误的,为什么?
在test3()中,指针是指向一个常数的,这是错误的,而指针应该指向一块地址。正确的定义初始化方式应该和2相同。
Test4()可以这样理解,p申请了一块动态内存,此时的指针p它已经指向了一块地址,但是还未初始化,*p=2的意思就是把这块地址赋值,使用之后申请的内存又被释放了。