2010-6-2
(一)
#include <stdio.h>
int ival = -1;
int main()
{
printf("%d\n", ::ival); // 全局
printf("%d\n", ival); // 依然是全局
int ival = 1; // 局部变量
printf("%d\n", ival++); // 打印的是局部
ival = 1;
printf("%d, %d, %d\n", ival, ival++, ival++); //printf 1 1 1
printf("%d\n", ival); //3
ival = 1;
printf("%d, %d, %d\n", ++ival, ++ival, ++ival); //4 3 2
ival = 1;
printf("%d, %d\n", ival++, ival); // 1 1
ival = 1;
printf("%d, %d\n", ++ival, ival);//2 1
return 1;
}
这段代码两个关心的问题:
1. 同一个变量名同时是全局和局部变量,在main函数中直接使用变量名,(1)main中没有定义同名的局部变量则访问全局变量,(2)main中定义了同名的局部变量,则访问局部变量。如果在main中采用::变量名的方式是访问,则访问的是全局变量。
2. printf函数的使用,在结合前加和后加的打印操作中,print自右向左压栈,如果是前加,则先加,再压栈,如果是后加(1)vc 6.0是先压栈,全部打印完成后再加;(2)g++,是先压栈一个,然后将其加1。上面这段程序的vc运行结果是:
-1
-1
1
1, 1, 1
3
4, 3, 2
1, 1
2, 1
2,1,1
Linux g++的运行结果:
-1
-1
1
3, 2, 1
3
4, 3, 2
1, 1
2, 1
4,2,1
(二)
C语言中各类型数据的长度:
(一)32位平台:
分为有符号型与无符号型。
有符号型:
short 在内存中占两个字节,范围为-2^15~(2^15-1)
int 在内存中占四个字节,范围为-2^31~(2^31-1)
long在内存中占四个字节,范围为-2^31~2^31-1
无符号型:最高位不表示符号位
unsigned short 在内存中占两个字节,范围为0~2^16-1
unsigned int 在内存中占四个字节,范围为0~2^32-1
unsigned long在内存中占四个字节,范围为0~2^32-1 // unsigned XXX与XXX的长度相同,只是取数范围不同;
实型变量:
分单精度 float 和双精度 double 两种形式:
float:占四个字节,提供7~8位有效数字。
double: 占八个字节,提供15~16位有效数字。
(二)16位平台:
1)整型(基本型):类型说明符为int,在内存中占2个字节。
2)短整型:类型说明符为short int或short。所占字节和取值范围均与整型(基本型)相同。
3)长整型:类型说明符为long int或long,在内存中占4个字节。
无符号型:类型说明符为unsigned。
无符号型又可与上述三种类型匹配而构成:
各种无符号类型量所占的内存空间字节数与相应的有符号类型量相同。但由于省去了符号位,故不能表示负数。
实型变量:
分为单精度(float型)、双精度(double型)和长双精度(long double型)三类。
单精度型占4个字节(32位)内存空间,其数值范围为3.4E-38~3.4E+38,只能提供七位有效数字。
双精度型占8 个字节(64位)内存空间,其数值范围为1.7E-308~1.7E+308,可提供16位有效数字。
长双精度型16 个字节(128位)内存空间,可提供18-19位有效数字。
(三)
int main()
{
unsigned char a = 0xA5;
unsigned int ta = ~a;
printf("~a = %d\n", ta);
unsigned char b = ~a>>4;
printf("b = %d\n", b);
printf("sizeof(int) = %d\n", sizeof(int));
printf("sizeof(short int) = %d\n", sizeof(short int));
printf("sizeof(long) = %d\n", sizeof(long));
return 0;
}
本题中,两点:(1)运算优先级问题:
优先级 | 运算符 | 含义 | 参与运算对象的数目 | 结合方向 |
1 | ( ) | 圆括号运算符 |
双目运算符 | 自左至右 |
2 | ! | 逻辑非运算符 | 单目运算符 | 自右至左 |
3 | * | 乘法运算符 | 双目运算符 | 自左至右 |
4 | + | 加法运算符 | 双目运算符 | 自左至右 |
5 | << | 左移运算符 | 双目运算符 | 自左至右 |
6 | < | 关系运算符 | 双目运算符 | 自左至右 |
7 | == | 判等运算符 | 双目运算符 | 自左至右 |
8 | & | 按位与运算符 | 双目运算符 | 自左至右 |
9 | ^ | 按位异或运算符 | 双目运算符 | 自左至右 |
10 | | | 按位或运算符 | 双目运算符 | 自左至右 |
11 | && | 逻辑与运算符 | 双目运算符 | 自左至右 |
12 | || | 逻辑或运算符 | 双目运算符 | 自左至右 |
13 | ?: | 条件运算符 | 三目运算符 | 自右至左 |
14 | = | 赋值运算符 | 双目运算符 | 自右至左 |
15 | , | 逗号运算符 |
| 自左至右 |
醋坛酸味灌
味落跳福豆
共44个运算符
醋-初等,4个: ( ) [ ] -> 指向结构体成员 . 结构体成员
坛-单目,9个: ! ~ ++ -- -负号 (类型) *指针 &取地址 sizeof长度 (结合方向:自右向左)
酸-算术,5个: * / % + -减
味-位移,2个: << >>
灌-关系,6个: < <= > >= == 等于 != 不等于
味-位逻,3个: & 按位与 ^ 按位异或 | 按位或
落-逻辑,2个: && 逻辑与 || 逻辑或
跳-条件,1个,三目: ? : (结合方向:自右向左)
福-赋值,11个: = += -= *= /= %= >>= <<= &= ^= |= (结合方向:自右向左)
豆-逗号,1个: ,
结合方向自右向左的只有三类:赋值、单目和三目,其它的都是从左至右结合。
2010-6-6
1. 关于union的组织方式和大小问题:
#include <iostream.h>
#include <stdio.h>
union DATE
{
char a;
int i[5];
double b;
};
struct date
{
int j; //4->(8)
DATE d; //24
float f; //4->(8)
};
DATE max;
/*
①联合就是一个结构,
②它的所有成员相对于基地址的偏移量都为0,
③此结构空间要大到足够容纳最“宽”的成员,
④并且,其对齐方式要适合于联合中所有类型的成员。
该结构要放得下int i[5]必须要至少占4×5=20个字节。
如果没有double的话20个字节够用了,此时按4字节对齐。
但是加入了double就必须考虑double的对齐方式,double是按照8字节对齐的,
所以必须添加4个字节使其满足8×3=24,也就是必须也是8的倍数,这样一来就出来了24这个数字。
综上所述,最终联合体的最小的size也要是所包含的所有类型的基本长度的最小公倍数才行。
(这里的字节数均指winnt下的值,平台、编译器不同值也有可能不同。)
Linux对本程序的运行结果与VC6.0不同!
*/
void main()
{
cout << sizeof(float) <<endl;
cout << sizeof( struct date ) << "\t " << sizeof(max) << "\t" << sizeof( union DATE) << endl;
}
3. 位段问题 Union_study _main4.cpp
4. 函数形参问题
函数在运行时首先将入参进行拷贝,这种拷贝是浅拷贝,即:数据和结构体是内容拷贝,指针式指针地址的拷贝,而不是指针的内容的拷贝。所以如果函数的入参是指针ptr,那么在运行时,会有一个临时的指针_ptr = ptr。(a)如果是给ptr新的地址,那么实际上是给临时变量_ptr赋值,ptr在调用函数之后没有改变。(b)如果ptr非空,即有具体的地址,那么_ptr也获得对应的地址,对形参_ptr的内存内容进行赋值或修改,也就是对ptr对应内存的内容进行修改,因为它们指向同一块内存。
对情形(a),换一种方式实现,将指针作为返回值,而不是在入参中作修改。
顺便关注一下与动态内存相关的问题:静态内存,栈内存和动态分配的内存(堆内存)的区别:
(1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
(2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意(只要内存能承受)多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
//关于指针变量的直接赋值,需要将整型数强制转换为整型指针,然后再赋值给指针变量
int *p = NULL;
p = (int*)(0x12ff7c);
*p = 0xaa55;
printf("\n%x\n", *p);
5. 关于for循环的顺序:
F:\JOB\笔记\code\_orderofsort
#include <stdio.h>
int main()
{
int a, x;
//注意:!(x++)等同于!x++,先判断x是否是0,然后将x递增1;
// 与!(x += 1)不同,它是先将x递增1,然后再判断x是否非零。
for( a = 0, x = 0/* 1 */; a <= 1 && !(x++)/* 2, 5 */; a++/* 4 */)
{
/* 3, 6 */
printf("x = %d, a = %d\n", x, a);
a++;
}
printf("%d, %d\n", a, x);
for (a = 0, x = 0; a <= 1 && !x++;)
{
a++;
}
printf("%d, %d\n",a, x);
return 0;
}
2010-9-3
void main()
{
cout << "------ 面试宝典 P76 --------" <<endl;
float (**def)[10];
float def0[10] = {0,1,2,3,4,5,6,7,8,9};
float (*def1)[10] = &def0;
def = &def1;
printf("%f\n", (**def)[4]);
}
def是指向一个地址54的指针50,地址54是数组的首位地址。
2010-9-5
void _strcat(char *des, char *src)
{
if (src == NULL)
{
return;
}
int i = 0, j = 0;
while(des[i++] != '\0');
i--;
while((des[i++] = src[j++]) != '\0');
}
EMC 的一道数论题
麦当劳有6块9块20块鸡的袋子,问大于等于N块的鸡都能正好用前述袋子装走的最小N是多少?正好的意思是每个袋子要么装满要么为空,答案是44
今天在网上看到的这个题,怎么做?
这个问题可以用不等式解决:
首先要满足:
6x + 9y + 20z = N; ..................式1
然后还要分析如何用这几种类型的袋子实现N+1;可以得到:
6(x+2) + 9(y+1) + 20(z-1) = N+1 ...............式2
不难发现这个式子是实现N+1的最有效方式。
然后再分析如何用这几种类型的袋子 实现N+2;可以得到:
6x + 9(y-2) + 20(z+1) = N+2 .................式3
同样,这也是实现N+2的最有效的方法(原因是只比原来多用了一个袋子)。
再分析如何用这同种类型的袋子 实现N+3;可以得到:
6(x-1) + 9(y+1) + 20z = N+3; .................式4
同样,这也是实现N+3的最有效的方法。
再往下实现N+4,N+5,N+6..........直到N+无穷,都可以用实现N+1,N+2,N+3这两种组合实现,所以只要找到满足式2,式3, 式4 的条件的x,y,z即可。
这里必须满 足的条件是 z-1 >= 0(由式2 得出)即-------->z >=1
y-2 >= 0(由式3 得出)即--------->y > = 2
x-1 >= 0(由式4得出)即---------->x > = 1
所以,6x + 9y + 20z >=44.
完毕。
6x + 9y + 20z = n 何时有非负解。
引用一个结论(《数论导引》,p11,华罗庚):
QUOTE:
设 (a,b)=1, a>0, b>0. 凡大于 ab-a-b 之数必可表为 ax+by (x>=0, y>=0) 之形。但 ab-a-b 不能表成此形。
6x+9y =n - 20z
3(2x+3y)=n-20z
2x+3y 可以在 x,y 非负的限制下,表示出大于 3*2-3-2 的整数,即 2,3,4,5....
所以 3(2x+3y) 可以表示 6, 9, 12,... , 即大于 3 的 3 的倍数。
(1) 若 n=0 (mod 3)
令 z=0, 则 n-20z 为 3 的倍数,只要 n>3 ,方程就有非负解
(2)若 n=1 (mod 3)
令 z=2, 则 n-20z=n-40 为 3 的倍数,只要 n-40>3,即 n>43,方程就有非负解
(3)若 n=2 (mod 3)
令 z=1, 则 n-20z=n-20 为 3 的倍数,只要 n-20>3,即使 n>23,方程就有非负解。
综合起来,知当 n>43 时,方程必有非负解。
而当 n=43 时, 3(2x+3y)=43-20z => z=0, 1, 2. 而仅当 z=2 时,43-20z 才是 3 的倍数。于是得到 2x+3y=1.
根据前面引用的结论,此时方程无非负解。
即:n=43 无非负解,n>43 时,有非负解。 done.