iOS (1) --C语言

1、当你写: least = MIN(*p++, b); 代码时会发生什么事?

结果是:((p++) <= (b) ? (p++) : (b)) 这个表达式会产生副作用,指针p会作两次++自增操作。

2、用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
(UL无符号长整形)

3、写一个"标准"宏MIN ,这个宏输入两个参数并返回较小的一个。

define MIN(A,B) ((A) <= (B) ? (A) : (B))

4、写一个标准宏Max,并给出以下代码的输出

int array[5] = {1, 2, 3, 4, 5};
int *p = &array[0];
int max = Max(*p++, 1);
printf("%d %d", max, *p);
参考答案: 1,2
#define Max(X, Y) ((X) > (Y) ? (X) : (Y))

注意:当看到宏时,就会想到宏定义所带来的副作用。
对于++、–,在宏当中使用是最容易产生副作用的,因此要慎用。

分析:
1> p指针指向了数组array的首地址,也就是第一个元素对应的地址,
其值为1。
2> 宏定义时一定要注意每个地方要加上圆括号
    *p++相当于*p, p++,所以Max(*p++, 1)相当于:
    (*p++) > (1) ? (*p++) : (1)
    =>
    (1) > (1) ? (*p++) : (1)
    =>
  第一个*p++的结果是,p所指向的值变成了2,但是1 > 1为假,
  所以最终max的值就是1。而后面的(*p++)也就不会执行,
3> 因此p所指向的地址对应的值就是2,而不是3.

扩展:
如果上面的*p++改成*(++p)如何?
(*++p) > (1) ? (*++p) : (1)
=>
(2) > (1) ? (*++p) : (1)
=> 
max = *++p;
=> 
*p = 3,max = 3;

5、define定义的宏和const定义的常量有什么区别?

#define定义宏的指令,程序在预处理阶段将用#define所定义
的内容只是进行了替换。
因此程序运行时,常量表中并没有用#define所定义的宏,
系统并不为它分配内存,而且在编译时不会检查数据类型,
出错的概率要大一些。

const定义的常量,在程序运行时是存放在常量表中,
系统会为它分配内存,而且在编译时会进行类型检查。
宏定义表达式时要注意“边缘效应”,例如如下定义:
#define N = 2 + 3 // 我们预想的N值是5,我们这样使用N
int a = N / 2;  // 我们预想的a的值是2.5,
可实际上a的值是3.5

6、关键字volatile有什么含意?并给出三个不同的例子

优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
1> 并行设备的硬件寄存器(如:状态寄存器)
2> 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3> 多线程应用中被几个任务共享的变量

7、static关键字的作用

1 > 隐藏。编译多个文件时,所有未加static前缀的全局变量和函数都全局可见。
2> 保持变量内容的持久。全局变量和static变量都存储在静态存储区,程序开始运行就初始化,只初始化一次。static控制了变量的作用范围。
3> 默认初始化为0.在静态数据区,内存中的所有字节都是0x00,全局变量和static变量都是默认初始化为0.

8、static关键字区别

1> static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
2> static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;  
3> static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝

9、关键字const

1> const int a;int const a; 作用是一样:a 是一个常整型数
2> const int *a;int const *a; a 是一个指向常整型数的指针(整型数是不可修改的,但指针可以)
3> int * const a;a 是一个指向整型数的常指针(指针指向的整型数是可以修改的,但指针是不可修改的)
4> int const * const a;a 是一个指向常整型数的常指针(指针指向的整型数是不可修改的,同时指针也是不可修改的)

10、堆栈

1> 管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生内存泄露 (memory leak)。
2>申请大小:
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在Windows下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示 overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
3> 碎片问题:
对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个 问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出
4> 分配方式:
堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由 alloc函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
5> 分配效率:
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的 效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的

11、数组和指针的区别

1> 数组可以申请在栈区和数据区;指针可以指向任意类型的内存块
2> sizeof作用于数组时,得到的是数组所占的内存大小;作用于指针时,得到的都是4个字节的大小
3> 数组名表示数组首地址,是常量指针,不可修改指向。比如不可以将++作用于数组名上;普通指针的值可以改变,比如可将++作用于指针上
4> 用字符串初始化字符数组是将字符串的内容拷贝到字符数组中;用字符串初始化字符指针是将字符串的首地址赋给指针,也就是指针指向了该字符串

12、引用和指针的区别

1> 指针指向一块内存,内容存储所指内存的地址。
2> 引用是某块内存的别名。
3> 引用使用时不需要解引用(*)而指针需要
4> 引用只在定义时被初始化,之后不可变,指针可变。
5> 引用没有const
6> 引用不能为空
7> sizeof引用得到的是所指向变量(对象)的大小,sizeof指针是指针本身的大小。
8> 指针和引用的自增(++)运算意义不一样:引用++为引用对象自己++,指针++是指向对象后面的内存
9> 程序需要为指针分配内存区域,引用不需要。

13、用变量a给出下面的定义

 一个整型数(An integer)
一个指向整型数的指针( A pointer to an integer)
一个指向指针的的指针,它指向的指针是指向一个整型数( A pointer to a pointer to an intege)r
一个有10个整型数的数组( An array of 10 integers)
一个有10个指针的数组,该指针是指向一个整型数的。(An array of 10 pointers to integers)
一个指向有10个整型数数组的指针( A pointer to an array of 10 integers)
一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument
and returns an integer)
一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions t
hat take an integer argument and return an integer )

答案是:
int a; // An integer
int *a; // A pointer to an integer
int **a; // A pointer to a pointer to an integer
int a[10]; // An array of 10 integers
int *a[10]; // An array of 10 pointers to integers
int (*a)[10]; // A pointer to an array of 10 integers
int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer 

14、请写出以下代码输出

int a[5] = {1, 2, 3, 4, 5};
int *ptr = (int *)(&a + 1);
printf("%d, %d", *(a + 1), *(ptr + 1));
参考答案: 2, 随机值
这种类型题好像挺常见的。考的就是C语言上的指针的理解和
数组的理解。
分析:
a代表有5个元素的数组的首地址,a[5]的元素分别是1,2,3,4,5。
接下来,a + 1表示数据首地址加1,那么就是a[1],
也就是对应于值为2.
但是,这里是&a + 1,因为a代表的是整个数组,
它的空间大小为5 * sizeof(int),因此&a + 1就是a+5。
a是个常量指针,指向当前数组的首地址,指针+1就是
移动sizeof(int)个字节。
因此,ptr是指向int *类型的指针,而ptr指向的就是a + 5,
那么ptr + 1也相当于a + 6,所以最后的*(ptr + 1)
就是一个随机值了。
而*(ptr – 1)就相当于a + 4,对应的值就是5。

15、简述内存分区情况

代码区:存放函数二进制代码
数据区:系统运行时申请内存并初始化,系统退出时由系统释放,存放全局变量、静态变量、常量
堆区:通过malloc等函数或new等操作符动态申请得到,需程序员手动申请和释放
栈区:函数模块内申请,函数结束时由系统自动释放,存放局部变量、函数参数

14、用NSLog函数输出一个浮点类型,结果四舍五入,并保留一位小数

float money = 1.011;
NSLog(@"%.1f", money);

你可能感兴趣的:(iOS (1) --C语言)