1. 下面代码的输出是什么?试着解释原因,说出你的理解
struct A {
long a;
int b;
};
int main(int argc, char* argv[])
{
struct A num = {0x6e694c756f796978,0x7875};
char ch = '0';
for(int i = 0; ch; i++)
{
ch = *((char *)&num + i);
printf("%c",ch);
}
printf("\n");
return 0;
}
num为struct A类型,0x6e694c756f796978为long类型,0x7875为int类型。
本题是16进制的ascii码,大小端的问题,还有结构体地址的题。
结构体的地址是相连的,所以a的地址后就是b的地址,所以根据根据地址一个个强制类型转换为char的地址,截取后得到的正好是一个字母的ascii,
for(int i = 0; ch; i++)
{
ch = *((char *)&num + i);
printf("%x ",ch);
}//输出78 69 79 6f 75 4c 69 6e 75 78 0
可以看出正好按两位两位的反转了,int类型的在long后,这就是小端的输出。
小端是低地址存储低字节,而long和int类型强制转化为char类型,就是截取最後面的地址,而小端模式下,最後面的地址正好存储低字节,就是数的最後位数,char类型为1字节,正好是2*8,正好是两个16进制的数字所占的。(大端模式是高地址存储低字节。)
int类型强制转化为char类型里输出0是因为获取到了0,是因为16进制00为char的ascii的0,而ascii的0为“\0”,所以获取到先得到0输出,然后发现结束了,後面的值不会再输出。
比如:
int main(){
int num=0x690078;
char ch='0';
for(int i = 0; ch; i++)
{
ch = *((char *)&num + i);
printf("%c",ch);
}
}
本来输出xi,结果中间加了00,只能输出x.
2. 改写代码,在不改变 const 的情况下尝试使用更多的方法改变b的值。
int main(int argc, char* argv[])
{
const int b = 10;
// 自行添加语句,改变变量b的值
return 0;
}
int main(int argc, char* argv[])
{
const int b = 10;
//1。
int*p=&b;
*p=2;
printf("%d\n",b);
//2.
int a=*&b;
a=2;
printf("%d\n",b);
//...(摸个鱼)
return 0;
}
3.阅读下面的代码,判断 a 中哪些元素被改变了,解释原因。
struct node {
char a;
int b;
short c;
};
struct n {
char a;
int b;
};
int main(int argc, char* argv[])
{
struct node a[2] = {
{1,2,3},{4,5,6}};
*(int *)((char *)a + 2 * sizeof(struct n)) = 100;
return 0;
}
a是结构体node的第一个元素,它的地址即结构体的首地址,所以a[2] = { {1,2,3},{4,5,6}},会修改结构体中的值。
struct node {
char a;
int b;
short c;
};
int main(int argc, char* argv[])
{
struct node a[2] = {
{1,2,3},{4,5,6}};
printf("%p %p &%p\n",&a->a,&a->b,&a->c);//0x7ffc694dbd60 0x7ffc694dbd64 &0x7ffc694dbd68
printf("%d %d %d\n",a->a,a->b,a->c);//1 2 3
return 0;
}
可以看出a,b,c三个不同类型储存了1,2,3。
对于*(int *)((char *)a + 2 * sizeof(struct n)),这个地址未赋值100前是什么?
sizeof(struct n)=8,(char*)a+2*sizeof(struct n)就是a[0]的地址加16*sizeof(char),即a[0]+4*sizeof(int),就是a[4](就是a[2]中的第5个数,这里用a[4]表示),即,*(int *)((char *)a + 2 * sizeof(struct n))=100,修改了a[4]的值。
4. 解释以下代码的输出结果。
void func(char* a)
{
printf("%lu\n", sizeof(a)) ;
printf("%lu\n", strlen(a)) ;
}
int main(int argc, char* argv[])
{
char a[] = "hello world";
char* b = "hello world";
printf("%s", b);
func(a);
printf("%lu\n", sizeof(a));
printf("%lu\n", strlen(a));
return 0;
}
结果:hello world
8
11
12
11
sizeof的作用是获取该变量占据的空间大小(包括‘\0’),strlen的作用是获取该字符串的长度。
可以看出两个sizeof(a)的结果不一样,那么肯定有不同点,仔细观察,就会发现,函数func的参数是个指针,指针的占据空间(64位下)永远是8。
5. 解释以下代码的输出结果。
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
int main(int argc, char* argv[])
{
printf("%s\n", h(f(1,2)));
printf("%s\n", g(f(1,2)));
return 0;
}
在宏定义里,a##b就是把a,b联接起来,,#a就是把a转化成字串,并合并。
那么h(f(1,2))=g(12)=12
g(f(1,2))=f(1,2)
6. lala 和 nini 是好朋友。有一天 lala 获得了 n 个质量不同的蛋糕,lala 想和 nini 一起分 享,让两个人都吃到相同质量的蛋糕。但是有强迫症的 lala 不想破坏每块蛋糕的完整 性,请编写程序判断这 n 个蛋糕是否符合 lala 的要求。
如有错误,请见谅。
int isaccord(double avge,double nums[],int size);
#define MAX 20
int main(){
int n=0;
double nums[MAX];
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lf",&nums[i]);
}
for(int gap=n/2;gap>0;gap/=2){
for(int i=gap;i<n;i++){
double t=nums[i];
int j=i-gap;
while(j>=0&&nums[j]>t){
nums[j+gap]=nums[j];
j-=gap;
}
nums[j+gap]=t;
}
}
double sum=0,avge=0;
for(int i=0;i<n;i++){
sum+=nums[i];
}
avge=sum/2;
int flag=isaccord(avge,nums,n);
if(flag==1){
printf("符合");
}else{
printf("不符合");
}
return 0;
}
int isaccord(double avge,double nums[],int size){
int flag=0;
double sum=0;
for(int i=0;i<size-1;i++){
sum=0;
for(int j=i;j<size;j++){
sum+=nums[j];
if(fabs(sum-avge)<0.0001){
flag=1;
return flag;
}
}
}
return flag;
}
其实排序可以用qsort()函数,我只是练练手希尔排序,很久没写了。
7. 编写函数实现以下功能:
输入: 一行字符串
输出:逆序输出字符串中的单词,不保留开头与结尾的空格,相邻单词间仅保留一个 空格 样例(❐ 代表空格):
输入: ❐❐❐❐Hello❐❐everyone,❐we❐are❐xiyouLinuxer❐
输出:xiyouLinuxer❐are❐we❐everyone,❐Hello
void reversePrint(char*str);
int main(){
char str[100];
// hello everyone, we are xiyou xiLinuxer
gets(str);
reversePrint(str);
return 0;
}
void reversePrint(char*str){
int l=strlen(str);
for(int i=l-1;i>=0;i--){
if(str[i]!=' '){
str[i+1]='\0';
break;
}
l--;
}
for(int i=l-1;i>=0;i--){
if(str[i]==' '){
printf("%s",&str[i+1]);
if(str[i]!=str[i-1]){
printf(" ");
}
if(str[i]==str[i-1]){
str[i-1]='\0';
}
str[i]='\0';
}
if(i==0&&str[0]!=' '){
printf("%s\n",&str[i]);
}
}
}
8. 下面这段程序有错吗?如果有错请指出并改正。
void func(char* p)
{
p = (char* )malloc(sizeof(char));
}
int main(int argc, char* argv[])
{
char* s = NULL;
func(s);
strcpy(s, "I love xiyou_linux");
puts(s);
return 0;
}
问题:1.改变一级指针,要通过二级指针。
2.申请的内存没有释放,也没有检查是否申请成功。
void func(char** p)
{
*p = (char* )malloc(sizeof(char)*20);
if(p==NULL){
fprintf(stderr,"malloc error\n");
exit(2);
}
}
int main(int argc, char* argv[])
{
char*s = NULL;
func(&s);
strcpy(s, "I love xiyou_linux");
puts(s);
return 0;
}
或者
char* func(char* p)
{
p = (char* )malloc(sizeof(char)*20);
if(p==NULL){
fprintf(stderr,"malloc error\n");
exit(2);
}
return p;
}
int main(int argc, char* argv[])
{
char*s = NULL;
s=func(s);
strcpy(s, "I love xiyou_linux");
puts(s);
return 0;
}
9. 在不创建新节点的情况下,逆置一个已给的链表。
Node* reverse(Node*head){
//我想不到不用新节点的办法,最多是只使用中间变量。
Node*t1=NULL,*t2=NULL;
t1=head->next;
head->next=NULL;//截断
while(t1!=NULL){
t2=t1;
t1=t1->next;
t2->next=head;
head=t2;
}
return head;
}
void print(Node*head){
Node*d=head;
while(d!=0){
printf("%d ",d->val);
d=d->next;
}
printf("\n");
}
int main(){
Node*head=NULL;
Node*p;
Node*last=NULL;
int num=0;
do{
scanf("%d",&num);
if(num!=-1)
{
p=(Node*)malloc(sizeof(Node*));
p->val=num;
p->next=NULL;
if(head){
last->next=p;
}
else{
head=p;
}
last=p;
}
}while(num!=-1);
print(head);
head=reverse(head);
print(head);
return 0;
}
10. 运行下列的代码,针对运行结果谈谈自己的理解。
int main(int argc, char* argv[])
{
char c = -1;
printf("%x\n", c);
printf("%x %d\n",
(unsigned char)c, (unsigned char)c);
}
运行结果:ffffffff
ff 255
有符号数把最高位当做符号位无符号数则把最高位正常看待,
%x的输出,其实是把字符型转成16进制整型输出,
char中 -1:直接输出c,就是ffffffff,
在(unsigned char)下10000001,转化为补码就是1111 1111 ,即ff ff,也是255,
如果字符型是有符号的,那么转成整型之后,内存占用32位 ,输出ffffffff
如果是有符号型,转换后就是认为是内存占8位,输出ff