数组指针定义 int (*p)[n];
()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。(从而指向下一个一维数组)
指针数组定义 int *p[n];
[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1时,则p指向下一个数组元素,,而且它们分别是指针变量可以用来存放变量地址。可以这样赋值 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。
a) 一个整型数(An integer)int a;
b) 一个指向整型数的指针(Apointer to an integer) int *a;
c) 一个指向指针的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer)int **a;
d) 一个有10个整型数的数组(An array of 10 integers) int a[10];
e) 一个有10个指针的数组,每个指针是指向一个整型数(An array of 10 pointers to integers)int *a[10];
f) 一个指向有10个整型数数组的指针(A pointer to an array of 10 integers) int (*a)[10];
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument andreturns an integer) int (*a)(int);
h) 一个有10个函数指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer argumentand return an integer )int (*a[10])(int);
请定义一个宏用于表示每一年有多少秒,忽视闰年的情况
#define SECOND_PER_YEAR (365 * 24 * 60 * 60UL)
|操作,当操作数为1时,结果为1,当操作数为0时,结果不变;
&操作,当操作数为1时,结果不变,当操作数为0时,结果为0
(第三个bit位在最低字节)
因此,设置a的bit 3为1的方法就是将a和00001000作|操作,这样其他位都不变,只有第3位变成1
清除a的bit3的方法就是将a和11110111作&操作,这样第3位变成0,其他位不变
设置a的bit3代码如下:
#include
int main()
{
int a;
printf("请输入一个整数");
scanf("%d",&a);
a=a|00000100;
printf("%d",a);
return 1;
}
清除a的bit3代码如下:
#include
int main()
{
int a;
printf("请输入一个整数");
scanf("%d",&a);
a=a&11111011;
printf("%d",a);
return 1;
}
方法一:算术运算法
a=a+b;
b=a-b;
a=a-b;
方法二:逻辑运算法
a=a^b;
b=a^b;
a=a^b;
#defineswap1(x, y) \
(y) = (x) + (y); \
(x) = (y) - (x); \
(y) = (y) - (x);
#defineswap2(x, y)\
x = x^y;\
y = x^y;\
x = x^y;
参与运算的两个值,如果两个相应位相同,则结果为0,否则为1。即:0^0=0, 1^0=1, 0^1=1, 1^1=0
例如:10100001^00010001=10110000
任何数异或自己,等于把自己置0
当调用delete的时候,系统会自动调用已分配的对象的析构函数。当我们用new [] 分配的对象是基本数据类型时,用delete和delete [] 没有区别。但是,当分配的对象是自定义对象时,二者不能通用。一般来说使用new分配的对象,用delete来释放。用new[] 分配的内存用delete [] 来逐个释放。
#define __max(a,b) (((a) > (b)) ? (a) : (b))
#define __min(a,b) (((a) < (b)) ? (a) : (b))
C++语言支持函数重载,C语言不支持函数重载,函数被C++编译器编译后在
库中的名字与C语言的不同,假设某个函数原型为:
void foo(int x,inty);
该函数被C编译器编译后在库中的名字为:
_foo
而C++编译器则会产生像:
_foo_int_int
之类的名字。为了解决此类名字匹配的问题,C++提供了C链接交换指定符号extern "C"。加上extern "C"表示该函数的编译与调用规则是C的规则
联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性就可以轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写。代码如下:
intcheckCPUendian()
{
union
{
unsigned int a;
unsigned char b;
}c;
c.a = 1;
return (c.b = =1);
}
/*return 1 :little-endian, return 0:big-endian*/
通用形式如下:
typedef int(*P)( ); // 定义一个函数指针P类型
P function( int(*p)( ) ); // 定义一个函数返回值P类型,且定义一个指向函数的指针p作参数
声明一个变量为只读。
下面的声明都是什么意思?
1)const int a; 2)int const a; 3)const int *a; 4)int * const a; 5) int const * const a ;
1,2一样a为只读整形变量;3 指向一个只读整形变量的指针;4 指向整形的只读指针; 5 指向只读整形的只读指针
int *p;
p=(int *) 0x1234; // 把整型数0x1234强制转换(typecast)为一指针
*p=0xaa55;
1、ISR不能有返回值;
2、ISR不能传递参数;
3、ISR应该是短而高效的,在ISR中做浮点运算是不明智的;
4、ISR中不应该有重入和性能上的问题,因此不应该使用pintf()函数。
#define在预编译的时候处理作机械的字符替换。typedef在编译的时候处理,并不是作简单的字符替换。而是如同定义变量一样声明一个类型。然后用它去定义这种类型的变量。
负数的反码:对原码除符号位外的其余各位逐位取反
负数的补码:对反码加1
正数的原码、反码、补码都一样
#include
char str[6]="12345";
int string_to_int(char s[])
{
int i;
int sum=0;
for(i=0;s[i]!='\0';i++)
{
sum=sum*10+s[i]-'0';
}
return sum;
}
int main(void)
{
printf("%d\n",string_to_int(str));
return 0;
}
#include
#include
#define LEN 4
char str[]=" ";
char *int_to_string(int given)
{
int i;
int temp;
for(i=0;i
temp=given/pow(10,LEN-1-i); // 从最高位开始
given=given%((int) pow(10,LEN-1-i));
str[i]=temp+'0';
}
return str;
}
int main(void)
{
printf("%s\n",int_to_string(9876));
return 0;
}
#include
int main(void)
{
int i, j;
for (i = 1; i <= 100; i++) {
for (j = 2; j < i; j++)
if (i % j == 0)
break;
if (j == i)
printf("%d\n", i);
}
return 0;
}
递归实现:
int factorial(int n)
{
if (n == 0)
return 1;
else {
int recurse = factorial(n-1);
int result = n * recurse;
return result;
}
}
循环实现:
int factorial(int n)
{
int result = 1;
while (n > 0) {
result = result * n;
n = n - 1;
}
return result;
}
#include
#define LEN 5
int a[LEN]={5,4,3,2,1};
void bubble_sort(void)
{
int i,j,flag=1;
int temp;
for(i=1;(i
flag=0;
for(j=0;j
if( a[j]>a[j+1] ){ // a[j]>a[j+1]从小到大;a[j]
flag=1;
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
printf("%d,%d,%d,%d,%d\n",a[0],a[1],a[2],a[3],a[4]);
}
}
//--------
int main(void)
{
bubble_sort();
return 0;
}
#include
#define LEN 5
int a[LEN]={7,4,8,4,5};
void insertion_sort(void)
{
int i,j,key;
for(j=1;j
printf("%d,%d,%d,%d,%d\n",a[0],a[1],a[2],a[3],a[4]);
key=a[j];
i=j-1;
while( (i>=0) && (a[i]>key) ){ //a[i]>key 从小到大; a[i]
a[i+1]=a[i];
i--;
}
a[i+1]=key;
}
printf("%d,%d,%d,%d,%d\n",a[0],a[1],a[2],a[3],a[4]);
}
//-----
int main(void)
{
insertion_sort();
return 0;
}
TCP/IP协议集包括应用层,传输层,网络层,网络访问层。
网络层包括: Internet协议(IP) Internet控制信息协议(ICMP) 地址解析协议(ARP) 反向地址解析协议(RARP)
网络访问层又称作主机到网络层(host-to-network).网络访问层的功能包括IP地址与物理地址硬件的映射,以及将IP封装成帧.基于不同硬件类型的网络接口,网络访问层定义了和物理介质的连接。
基本区别
1.基于连接与无连接
2.TCP要求系统资源较多,UDP较少;
3.UDP程序结构较简单
4.流模式(TCP)与数据报模式(UDP);
5.TCP保证数据正确性,UDP可能丢包
6.TCP保证数据顺序,UDP不保证
编程区别
通常我们在说到网络编程时默认是指TCP编程,即用前面提到的socket函数创建一个socket用于TCP通讯,函数参数我们通常填为SOCK_STREAM。即socket(PF_INET, SOCK_STREAM, 0),这表示建立一个socket用于流式网络通讯。
SOCK_STREAM这种的特点是面向连接的,即每次收发数据之前必须通过connect建立连接,也是双向的,即任何一方都可以收发数据,协议本身提供了一些保障机制保证它是可靠的、有序的,即每个包按照发送的顺序到达接收方。
而SOCK_DGRAM这种是User DatagramProtocol协议的网络通讯,它是无连接的,不可靠的,因为通讯双方发送数据后不知道对方是否已经收到数据,是否正常收到数据。任何一方建立一个socket以后就可以用sendto发送数据,也可以用recvfrom接收数据。根本不关心对方是否存在,是否发送了数据。它的特点是通讯速度比较快。大家都知道TCP是要经过三次握手的,而UDP没有。
通常操作系统把进程作为分配资源的基本单位,而把线程作为独立运行和CPU独立调度的基本单位。
多核处理器下,会存在多个进程处于内核态的情况,而在内核态下,进程是可以访问所有内核数据的,因此要对共享数据进行保护,即互斥处理。
信号量mutex是sleep-waiting。就是说当没有获得mutex时,会有上下文切换,将自己、加到忙等待队列中,直到另外一个线程释放mutex并唤醒它,而这时CPU是空闲的,可以调度别的任务处理。
而自旋锁spin lock是busy-waiting。就是说当没有可用的锁时,就一直忙等待并不停的进行锁请求,直到得到这个锁为止。这个过程中cpu始终处于忙状态,不能做别的任务。
例如在一个双核的机器上有两个线程(线程A和线程B),它们分别运行在Core0 和Core1上。用spin-lock,coer0上的线程就会始终占用CPU。
另外一个值得注意的细节是spin lock耗费了更多的usertime。这就是因为两个线程分别运行在两个核上,大部分时间只有一个线程能拿到锁,所以另一个线程就一直在它运行的core上进行忙等待,CPU占用率一直是100%;而mutex则不同,当对锁的请求失败后上下文切换就会发生,这样就能空出一个核来进行别的运算任务了。
简单地说作用就是防止编译器对代码进行优化。比如如下程序:
XBYTE[2]=0x55;
XBYTE[2]=0x56;
XBYTE[2]=0x57;
XBYTE[2]=0x58;
对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器却会对上述四条语句进行优化,认为只有XBYTE[2]=0x58(即忽略前三条语句,只产生一条机器代码)。如果键入volatile,则编译器会逐一地进行编译并产生相应的机器代码(产生四条代码)。
精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。