1.#include <stdio.h>
2.#include <stdlib.h>
3.#include <unistd.h>
4.#include <pthread.h>
5.
6.int golobal_a = 0; //定义全局变量
7.
8.int main()
9.{
10. int local_a = 0; //定义局部变量
11. pthread_mutex_t local_mutex_a; //定义线程互斥锁
12. pthread_mutex_t local_mutex_b;
13. pid_t pid;
14.
15. pthread_mutex_init(&local_mutex_a, NULL); //线程互斥锁初始化
16. pthread_mutex_init(&local_mutex_b, NULL);
17. pid = fork(); //fork子进程
18.
19. if(pid > 0) { //父进程里 修改了全局变量和局部变量
上锁解锁
20. printf("father %d, child %d\n", getpid(), pid);
21. local_a = 1;
22. golobal_a = 1;
23. sleep(1);
24. printf("father local_a %d, addr %p, golobal_a %d, addr %p\n", local_a, &local_a, golobal_a,
&golobal_a);
25.
26. pthread_mutex_lock(&local_mutex_a);
27. printf("father lock mutex a %p\n", &local_mutex_a);
28. sleep(1);
29. pthread_mutex_lock(&local_mutex_b);
30. printf("father lock mutex b %p\n", &local_mutex_b);
31. pthread_mutex_unlock(&local_mutex_b);
32. pthread_mutex_unlock(&local_mutex_a);
33. } else if (pid == 0) { //子进程里 修改了全局变量和局部变量
上锁解锁
34. printf("child %d\n", getpid());
35. local_a = 2;
36. golobal_a = 2;
37. sleep(1);
38. printf("child local_a %d, addr %p, golobal_a %d, addr %p\n", local_a, &local_a, golobal_a,
&golobal_a);
39.
40. pthread_mutex_lock(&local_mutex_b);
41. printf("child lock mutex b %p\n", &local_mutex_b);
42. sleep(1);
43. pthread_mutex_lock(&local_mutex_a);
44. printf("child lock mutex a %p\n", &local_mutex_a);
45. pthread_mutex_unlock(&local_mutex_a);
46. pthread_mutex_unlock(&local_mutex_b);
47. } else
48. printf("fork fail\n");
49.
50. return 0;
51.}
2.#include <stdlib.h>
3.#include <unistd.h>
4.#include <pthread.h>
5.
6.int golobal_a = 0; //定义全局变量
7.
8.int main()
9.{
10. int local_a = 0; //定义局部变量
11. pthread_mutex_t local_mutex_a; //定义线程互斥锁
12. pthread_mutex_t local_mutex_b;
13. pid_t pid;
14.
15. pthread_mutex_init(&local_mutex_a, NULL); //线程互斥锁初始化
16. pthread_mutex_init(&local_mutex_b, NULL);
17. pid = fork(); //fork子进程
18.
19. if(pid > 0) { //父进程里 修改了全局变量和局部变量
上锁解锁
20. printf("father %d, child %d\n", getpid(), pid);
21. local_a = 1;
22. golobal_a = 1;
23. sleep(1);
24. printf("father local_a %d, addr %p, golobal_a %d, addr %p\n", local_a, &local_a, golobal_a,
&golobal_a);
25.
26. pthread_mutex_lock(&local_mutex_a);
27. printf("father lock mutex a %p\n", &local_mutex_a);
28. sleep(1);
29. pthread_mutex_lock(&local_mutex_b);
30. printf("father lock mutex b %p\n", &local_mutex_b);
31. pthread_mutex_unlock(&local_mutex_b);
32. pthread_mutex_unlock(&local_mutex_a);
33. } else if (pid == 0) { //子进程里 修改了全局变量和局部变量
上锁解锁
34. printf("child %d\n", getpid());
35. local_a = 2;
36. golobal_a = 2;
37. sleep(1);
38. printf("child local_a %d, addr %p, golobal_a %d, addr %p\n", local_a, &local_a, golobal_a,
&golobal_a);
39.
40. pthread_mutex_lock(&local_mutex_b);
41. printf("child lock mutex b %p\n", &local_mutex_b);
42. sleep(1);
43. pthread_mutex_lock(&local_mutex_a);
44. printf("child lock mutex a %p\n", &local_mutex_a);
45. pthread_mutex_unlock(&local_mutex_a);
46. pthread_mutex_unlock(&local_mutex_b);
47. } else
48. printf("fork fail\n");
49.
50. return 0;
51.}
1.father 17164, child 17165
2.child 17165
3.father local_a 1, addr 0x7fff1793d298, golobal_a 1, addr 0x601070
4.father lock mutex a 0x7fff1793d2a0
5.child local_a 2, addr 0x7fff1793d298, golobal_a 2, addr 0x601070
6.child lock mutex b 0x7fff1793d2d0
7.father lock mutex b 0x7fff1793d2d0
8.child lock mutex a 0x7fff1793d2a0
分析:因为在fork之前就定义了全局,局部,互斥锁,所以在父子进程中都有,都可以对其进行修改,但各个变量的虚拟地址是一
样的,物理地址不一样。
*******************************************************************************************************************
*******
使用gdb调试的时候,gdb只能跟踪一个进程。可以在fork函数调用之前,通过指令设置gdb调试工具跟踪父进程或者是跟踪子进程。
默认跟踪父进程。
set follow_fork_mode parent设置跟踪父进程
*******************************************************************************************************************
*******
数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。数组名对应着(而不是指向)一块内存,其地址与容量在生命
期内保持不变,
只有数组的内容可以改变。
2.child 17165
3.father local_a 1, addr 0x7fff1793d298, golobal_a 1, addr 0x601070
4.father lock mutex a 0x7fff1793d2a0
5.child local_a 2, addr 0x7fff1793d298, golobal_a 2, addr 0x601070
6.child lock mutex b 0x7fff1793d2d0
7.father lock mutex b 0x7fff1793d2d0
8.child lock mutex a 0x7fff1793d2a0
分析:因为在fork之前就定义了全局,局部,互斥锁,所以在父子进程中都有,都可以对其进行修改,但各个变量的虚拟地址是一
样的,物理地址不一样。
*******************************************************************************************************************
*******
使用gdb调试的时候,gdb只能跟踪一个进程。可以在fork函数调用之前,通过指令设置gdb调试工具跟踪父进程或者是跟踪子进程。
默认跟踪父进程。
set follow_fork_mode parent设置跟踪父进程
*******************************************************************************************************************
*******
数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。数组名对应着(而不是指向)一块内存,其地址与容量在生命
期内保持不变,
只有数组的内容可以改变。
指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存。指针远比数组灵活,但也更危险。
*******************************************************************************************************************
*******
strcpy提供了字符串的复制。即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符。
*******************************************************************************************************************
*******
strcpy提供了字符串的复制。即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符。
已知strcpy函数的原型是:;
char* strcpy(char* dest, const char* src)
{
char* tmp=dest;
while{(*dest++=*src++)!='\0'};
return tmp;
}
memcpy提供了一般内存的复制。即memcpy对于需要复制的内容没有限制,因此用途更广。
void *memcpy( void *dest, const void *src, size_t count ){
char* pdest=static_cast<char*>(dest);
const char* psrc=static_cast<const char*>(src);
if(pdest==NULL||psrc==NULL)
return NULL;
else if(pdest>psrc&&pdest<psrc+count)
{
for(size_t i=count-1;i>0;i--) pdest[i]=psrc[i];
}
else{
for(i=0;i<count-1;i++) pdest[i]=psrc[i];
}
return pdest;
}
char* strcpy(char* dest, const char* src)
{
char* tmp=dest;
while{(*dest++=*src++)!='\0'};
return tmp;
}
memcpy提供了一般内存的复制。即memcpy对于需要复制的内容没有限制,因此用途更广。
void *memcpy( void *dest, const void *src, size_t count ){
char* pdest=static_cast<char*>(dest);
const char* psrc=static_cast<const char*>(src);
if(pdest==NULL||psrc==NULL)
return NULL;
else if(pdest>psrc&&pdest<psrc+count)
{
for(size_t i=count-1;i>0;i--) pdest[i]=psrc[i];
}
else{
for(i=0;i<count-1;i++) pdest[i]=psrc[i];
}
return pdest;
}
strcpy和memcpy主要有以下3方面的区别:
1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个
参数决定复制的长度。
3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy
*******************************************************************************************************************
*******
(4)在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;
(5)在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。
*******************************************************************************************************************
*******
9. 结构(struct)和联合(union)的区别?
1) 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合转只存放了一个被选中的成员,
而结构的所有成员都存在。
1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个
参数决定复制的长度。
3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy
*******************************************************************************************************************
*******
(4)在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;
(5)在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。
*******************************************************************************************************************
*******
9. 结构(struct)和联合(union)的区别?
1) 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合转只存放了一个被选中的成员,
而结构的所有成员都存在。
2) 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的.
*******************************************************************************************************************
*******
10. 类(class)与结构(struct)的区别?
*******************************************************************************************************************
*******
10. 类(class)与结构(struct)的区别?
(1)默认的继承访问权限: struct是public的,class是private的;
(2)class是引用类型,struct是值类型;
(3)class可以继承类、接口和被继承,struct只能继承接口,不能被继承;
(4)class有默认的无参构造函数,有析构函数,struct没有默认的无参构造函数,且只能声明有参的构造函数,没有析构函数;
(5)class可以使用abstract和sealed(密封的),有protected修饰符,struct不可以用abstract和sealed,没有protected修饰符;
(6)class必须使用new初始化,结构可以不用new初始化;
(7) class实例由垃圾回收机制来保证内存的回收处理,而struct变量使用完后立即自动解除内存分配;
(2)class是引用类型,struct是值类型;
(3)class可以继承类、接口和被继承,struct只能继承接口,不能被继承;
(4)class有默认的无参构造函数,有析构函数,struct没有默认的无参构造函数,且只能声明有参的构造函数,没有析构函数;
(5)class可以使用abstract和sealed(密封的),有protected修饰符,struct不可以用abstract和sealed,没有protected修饰符;
(6)class必须使用new初始化,结构可以不用new初始化;
(7) class实例由垃圾回收机制来保证内存的回收处理,而struct变量使用完后立即自动解除内存分配;
从职能观点来看,class表现为行为,而struct常用于存储数据;
作为参数传递时,class变量以按址方式传递,而struct变量是以按值方式传递的。
深拷贝指的就是当拷贝对象中有对其他资源(如堆、文件、系统等)的引用时(引用可以是指针或引用),对象会另开辟一块新的
资源,*而不再对拷贝对象中有对其他资源的引用的指针或引用进行单纯的赋值*。
设计了一个没有类而没有提供它的复制构造函数,当用该类的一个对象去给另一个对象简单赋值的过程就是浅拷贝,会把指针也
简单复制,到析构的时候,(假如指针是指向先定义的那个对象申请的堆空间,简单复制后,浅拷贝生成的对象里的指针也指向
同一区域),重复析构造成程序崩溃
*******************************************************************************************************************
*******
main 函数之前执行:
一些全局变量、对象和静态变量、对象的空间分配和赋初值就是在执行main函数之前;
main函数执行完后,还要去执行一些诸如释放空间、释放资源使用权等操作
全局对象的析构函数会在main函数之后执行;
用atexit注册的函数也会在main之后执行。
*******************************************************************************************************************
*******
char* Reverse(char* s) //字符串逆序
{
//将q指向字符串最后一个字符
char* q = s ;
while( *q++ ) ;
q -= 2 ;
深拷贝指的就是当拷贝对象中有对其他资源(如堆、文件、系统等)的引用时(引用可以是指针或引用),对象会另开辟一块新的
资源,*而不再对拷贝对象中有对其他资源的引用的指针或引用进行单纯的赋值*。
设计了一个没有类而没有提供它的复制构造函数,当用该类的一个对象去给另一个对象简单赋值的过程就是浅拷贝,会把指针也
简单复制,到析构的时候,(假如指针是指向先定义的那个对象申请的堆空间,简单复制后,浅拷贝生成的对象里的指针也指向
同一区域),重复析构造成程序崩溃
*******************************************************************************************************************
*******
main 函数之前执行:
一些全局变量、对象和静态变量、对象的空间分配和赋初值就是在执行main函数之前;
main函数执行完后,还要去执行一些诸如释放空间、释放资源使用权等操作
全局对象的析构函数会在main函数之后执行;
用atexit注册的函数也会在main之后执行。
*******************************************************************************************************************
*******
char* Reverse(char* s) //字符串逆序
{
//将q指向字符串最后一个字符
char* q = s ;
while( *q++ ) ;
q -= 2 ;
//分配空间,存储逆序后的字符串。
char* p = newchar[sizeof(char) * (q - s + 2)] ;
char* r = p ;
char* p = newchar[sizeof(char) * (q - s + 2)] ;
char* r = p ;
// 逆序存储
while(q >= s)
*p++ = *q-- ;
*p = '\0' ;
while(q >= s)
*p++ = *q-- ;
*p = '\0' ;
return r ;
}
}