*(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5 76、 void getmemory(char *p) {
p=(char *) malloc(100); strcpy(p,\world\ }
int main( ) {
char *str=NULL; getmemory(str); printf(\ free(str); return 0; }
程序崩溃,getmemory中的malloc 不能返回动态内存, free()对str操作很危险 77、void GetMemory(char *p) {
p = (char *)malloc(100); }
void Test(void) {
char *str = NULL; GetMemory(str); strcpy(str, \world\ printf(str); }
请问运行Test函数会有什么样的结果?
答:程序崩溃。因为GetMemory并不能传递动态内存,Test函数中的 str一直都是 NULL。strcpy(str, \world\将使程序崩溃。 void GetMemory2(char **p, int num) {
*p = (char *)malloc(num); }
void Test(void) {
char *str = NULL; GetMemory(&str, 100); strcpy(str, \ printf(str); }
请问运行Test函数会有什么样的结果? 答:(1)能够输出hello (2)内存泄漏
78、char *GetMemory(void) {
char p[] = \world\ return p; }
void Test(void) {
char *str = NULL; str = GetMemory(); printf(str); }
请问运行Test函数会有什么样的结果?
答:可能是乱码。因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是 NULL, 但其原现的内容已经被清除,新内容不可知。 79、void Test(void) {
char *str = (char *) malloc(100); strcpy(str, “hello”); free(str); if(str != NULL) {
strcpy(str, “world”); printf(str); } }
请问运行Test函数会有什么样的结果?
答:篡改动态内存区的内容,后果难以预料,非常危险。因为free(str);之后,str成为野指针,
if(str != NULL)语句不起作用。
野指针不是NULL指针,是指向被释放的或者访问受限内存指针。 造成原因:指针变量没有被初始化任何刚创建的指针不会自动成为NULL; 指针被free或delete之后,没有置NULL;
指针操作超越了变量的作用范围,比如要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放。
80、unsigned char *p=(unsigned char *)0x0801000 unsigned char *q=(unsigned char *)0x0810000 p+5 =? 0x0801005 q+5 =? 0x0810005
81、进程间通信方式:管道、命名管道、消息队列、共享内存、信号、信号量、套接字。 (1)、 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。
进程的亲缘关系通常是指父子进程关系。
(2)、有名管道 (named pipe) :有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
(3)、信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。 它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。 因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
(4)、消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。
消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 (5)、信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。 (6)、共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存, 这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制, 如信号两,配合使用,来实现进程间的同步和通信。
(7)、套接字( socket ) : 套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。 82、宏和函数的优缺点?
(1)、函数调用时,先求出实参表达式的值,然后带入形参。而使用带参数的宏只是进行简单的字符替换。
(2)、函数调用是在程序运行时处理的,分配临时的内存单元;而宏展开则是在编译时进行的,在展开时并不分配内存单元,
不进行值的传递处理,也没有“返回值”的概念。
(3)、对函数中的实参和形参都要定义类型,二者的类型要求一致,应进行类型转换;而宏不存在类型问题,宏名无类型,
它的参数也是无类型,只是一个符号代表,展开时带入指定的字符即可。宏定义时,字符串可以是任何类型的数据。
(4)、调用函数只可得到一个返回值,而宏定义可以设法得到几个结果。
(5)、使用宏次数多时,宏展开后源程序长,因为每次展开一次都使程序增长,而函数调用不使源程序变长。
(6)、宏替换不占运行时间,只占编译时间;而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。 83、C和c++的不同
c和c++的一些不同点(从语言本身的角度):
1)c++源于c,c++最重要的特性就是引入了面向对象机制,class关键字。 2)c++中,变量可以再任何地方声明;c中,局部变量只能在函数开头声明。 3)c++中,const型常量是编译时常量;c中,const常量只是只读的变量。 4)c++有&引用;c没有
5)c++的struct声明自动将结构类型名typedef;c中struct的名字只在结构标签名字空间中,不是作为一种类型出现
6)c语言的main函数可以递归调用;c++中则不可以
7)c中,void *可以隐式转换成其他指针类型;c++中要求现实转换,否则编译通不过 84、6.大小端格式问题。 方法一:
void checkCpuMode(void) {
int i = 0x12345678; char *cp = (char *)&i; if(*cp == 0x78) printf(\endian\ else
printf(\endian\\n\ } 方法二:
void checkCpuMode(void) {
int a = 0x12345678; if((char)a == 0x12)
printf(\endian\\n\ else
printf(\endian\\n\ } 方法三:
void checkCpuMode(void) { union { short s;
char c[sizeof(short)]; }un;
un.s=0x0102;
if(un.[0]==1&&un.c[1]==2) printf(\endian\\n\ else
printf(\endian\\n\ }
85、由C/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack): 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap): 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。 注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
3、全局区(static): 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,
未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后有系统释放 。
4、文字常量区: 常量字符串就是放在这里的, 程序结束后由系统释放。 5、程序代码区: 存放函数体的二进制代码。 87、for(m=5;m--;m<0) {
printf(\ }输出:4、3、2、1、0
88、5[\能够编译通过,请问编译后的结果是什么?
printf(\输出'f'的ACSII值,如果是4[\则输出'e'的ACSII的值。