实验室暑假第一次测试总结
前言
这个第一次测试写下来总体来说不太理想,尽管学长已经很有心承上启下来安排题目,规划以后学习路线,但我对于以前的基础题还是忘的有点多,或者对于前半年所学的自我感觉有失偏颇,总之,没有写好,以后要多加努力啊。。
1. 阅读下面代码段,回答问题
typedef struct tag_unimportant {
char *t2;
int t1;
} A;
void func(A *a)
{
a = (A *)malloc(sizeof(A));
a->t1 = 0x20200011;
a->t2 = (char* )&(a->t1);
*(a->t2) = 0x00;
//strcpy(a->t2, "xiyoulinux");
}
int main(int argc, char *argv[])
{
A *a;
func(a);
printf("%x\n", a->t1);
//printf(“%s\n”, a->t2);
return 0;
}
1). 以下代码段存在问题, 请在不修改结构体定义,不减少功能的前提下对此对此代码
中存在的问题进行修改并说明修改原因。
2). 修改正确后,写出输出结果并说明原因
3). 将注释加入程序, 能正确运行吗, 如果能, 输出结果是什么, 并说明原因
4). sizeof(A)的结果是什么,为什么,再定义一个 int 类型的 t3, 定义的位置影响结果吗,
说明理由。
- 第一问有两种解法,你要么是去主函数开辟结构体堆大小,要么改用二级指针进行地址值传递
改正后
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct tag_unimportant
{
char *t2;
int t1;
} A;
void func(A **a)
{
//*a =(A *)malloc(sizeof(A));
(*a)->t1 = 0x20200011;
*((*a)->t2) = 0x00;
strcpy((*a)->t2, "xiyoulinux");
}
int main(int argc, char *argv[])
{
A *a;
a=(A*)malloc(sizeof(A));
func(a);
printf("%x\n", a->t1);
printf("%s\n", a->t2);
}
或
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct tag_unimportant
{
char *t2;
int t1;
} A;
void func(A **a)
{
*a =(A *)malloc(sizeof(A));
(*a)->t1 = 0x20200011;
(*a)->t2 = (char* )&((*a)->t1);
*((*a)->t2) = 0x00;
strcpy((*a)->t2, "xiyoulinux");
}
int main(int argc, char *argv[])
{
A *a;
func(&a);
printf("%x\n", a->t1);
printf("%s\n", a->t2);
}
- 第二问略
- 第三问有点意思,首先我们先明确结构体里面t1所在的地址值为
0x20200011
下一步强转(char*)
后t2所在的地址值为0x00000011
因为一开始t1的类型是int
,占四个字节,所在的内存分别是0x0000
,0x0001
,0x0002
,0x0003
0x0000 0x0001 0x0002 0x0003
11 00 20 20
小端模式从低地址读到高地址
强转后为
0x0000 0x0001 0x0002 0x0003
11 00 00 00
char
类型指针,占前面一个地址,即内存0x0000
的内容,后面补齐三个字节
这时的t2是0x00000011
,解引用赋值后为0x00
,即为0
补:如果我们要强转(short*)或者(float*)呢,请写出答案
之后strcpy()复制xiyoulinux
到t2,但是由于t2空间大小,可能会栈溢出,为不可知的值,这是一个不安全的方法,建议改用memcpy
和strncpy
2.分析代码并说明:
a. 最终输出多少次"hello, world?"
b. printf 加上换行符,最终输出多少次"hello, world?";
c. 最终将产生共多少个进程。
int main(int argc, char *argv[])
{
for (int i = 0; i < 2; i++)
{
pid_t pid = fork();
printf("hello, world?");
}
}
a. 8
b.6
c.4
- 第一个的问题是printf是向标准输出(stdout)输出你要打印的东西,而默认的stdout是行缓存的,
所以当你打印的东西不够一行(没有\n)的时候,这些信息是保存在stdout的buffer
首先进行fork()
,这样父进程和子进程的stdout的buffer就都包含有你没有打印出来的内容(因为没有换行符),第二次fork()
,原先的父进程产生新的子进程,原先的子进程产生新的子程,这时就有四个进程,缓冲区里面有四个hello world
,经过两次循环,buffer中的内容会被打印出二次 - 第二题同理,只不过打印的东西够了一行(有\n结束符),于是在第一次fork()时就会打印两个,接着fork()后有四个进程,便会打印四个,一共六个
- 略
3. 僵尸进程和孤儿进程是什么?分明写代码复现。
略
4. 有两个线程在并发执行以下代码段,其中 g 是 int 类型的全局变量。请问当两个线程都执行完毕该代码段后,g 的值的取值范围为
for (int i = 1; i <= 50000; i++)
{
g += 1;
}
50000-100000
这方面有点涉及编译器原理,可能解释的有点不准确
50000 : 第一个线程+1,第二个线程也+1,这种情况虽然二个线程都对g加1,但显然只加了一次。所以到最后只加50000次
100000 : 第一个线程的for结束,再到第二个线程的for结束,一共执行100000次
5.编写一个至少具有三个线程的程序(称之为线程 A、B 和 C),其中线程 A 输出字符’A’,线程 B 输出字符’B’,线程 C 输出字符’C’。使得最终输出结果为“ABCABCABC…”。
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
#include<stdlib.h>
sem_t sem[3];
void* fun1(void* arg)
{
while(1)
{
sem_wait(&sem[0]);
printf("A");
sem_post(&sem[1]);
}
}
void* fun2(void* arg)
{
while(1)
{
sem_wait(&sem[1]);
printf("B");
sem_post(&sem[2]);
}
}
void* fun3(void* arg)
{
while(1)
{
sem_wait(&sem[2]);
printf("C");
sem_post(&sem[0]);
}
}
int main()
{
pthread_t tid,cid,gid;
sem_init(&sem[0],0,1);
sem_init(&sem[1],0,0);
sem_init(&sem[2],0,0);
pthread_create(&tid,NULL,fun1,NULL);
pthread_create(&cid,NULL,fun2,NULL);
pthread_create(&gid,NULL,fun3,NULL);
pthread_join(tid,NULL);
pthread_join(cid,NULL);
pthread_join(gid,NULL);
sem_destroy(&sem[0]);
sem_destroy(&sem[1]);
sem_destroy(&sem[2]);
}
是时候复习一下信号量了,我拿锁没写出来。。害
本文地址:https://blog.csdn.net/weixin_45819130/article/details/107597854
下一篇: 爱普生tw740对比tw750哪个更好
推荐阅读