int main(void) {
char* p1 = "abc";
char* p2 = (char*)malloc(sizeof(char) * 3);
char* p3 = (char*)memcpy(p2, p1, 3);
printf("p2 = %s\np3 = %s\n", p2, p3);
free(p2);
p2 = NULL;
p3 = NULL;
system("pause");
return 1;
}
打印结果:乱码
p2 = abc?
p3 = abc?
请按任意键继续. . .
int main(void) {
char* p1 = "abc";
char* p2 = (char*)malloc(sizeof(char) * 4);
char* p3 = (char*)memcpy(p2, p1, 4);
printf("p2 = %s\np3 = %s\n", p2, p3);
free(p2);
p2 = NULL;
p3 = NULL;
system("pause");
return 1;
}
打印结果:正常
p2 = abc
p3 = abc
请按任意键继续. . .
并行设备的硬件寄存器(如:状态寄存器)
一个中断服务子程序中会访问到的非自动变量(如下例子)
多线程应用中被几个任务共享的变量
int time = 0;
int main()
{
if(time == 10)
{
dothing();//不会正确执行
}
}
void isr_tick()
{
time = 10;
}
例子中dothing()可能永远不会执行,一直使用的是“tme = 0”的副本i,不是读取i原始地址的值;time在中断中改变后main函数不会读取到。
有位博主说:volatile应该解释为“直接从原始内存地址读值”比较合适,“易变的”这种解释有点误导人。这个理解不错。
void itoa ( int n,char s[])
{
int i,j,sign;//数字太大要使用unsigned long
char tmp;
if((sign=n)<0)//负数时使用
{
n=-n;
}
i=0;
do
{
s[i++]=n%10+'0';//从个位开始 ,循环取个位 十位 百位...放进s[0] s[1] s[2]
}
while ((n/=10)>0);
if(sign<0) //负数时使用
{
s[i++]='-';
}
s[i]='\0'; //字符串要加终止符
if(i <= 0) return;
for(j=0;j<=(i/2);j++)//FROM 0~(i/2),之前是倒序,这里再逆序排一遍
{
tmp = s[j];
s[j] = s[i-j-1];
s[i-j-1] = tmp;
}
}
定义int a2[ ],则a2[ ]中的每个元素占一个int,一般机器上也就是4个字节。
而memcpy第三个参数为字节数,所以:
memcpy(a1,a2, sizeof(int) * 10 ); //复制了40个字节,赋值正确
memcpy(a1,a2,10); //只复制了10个字节,赋值异常
void main(void) {
int i = 0;
int a2[] = {1,2,3,4,5,6,7,8,9,10};
int a1[10];
memcpy(a1,a2, sizeof(int)*10);
while(i<10)
{
printf("%d\n",a1[i]);
i++;
}
}
自定义的格式也要用sizeof():
typedef unsigned short uint16;
uint16 a2[] = {1,2,3,4,5,6,7,8,9,10};
uint16 a1[10];
memcpy(a1,a2, sizeof(uint16 )*10);
这里再提一下指针的加减,[a2 + 2]不是代表a2后移多少个字节,而是代表指针后移两个元素,即*a1 = a2[2] = 3。
uint16 a2[] = {1,2,3,4,5,6,7,8,9,10};
uint16 *a1;
a1 = a2 + 2;
printf("%d\n",*a1);
下面示例可以帮助理解以上内容:
eg:把二维数组第0行100个元素拷贝给a0,第1行100个元素拷贝给a1:
uint16 a[2][100] = 略;
uint16 a0[100];
uint16 a1[100];
//把二维数组第0行100个元素拷贝给a0:
memcpy(a0,a, sizeof(uint16 )*100);//此时指针a指向a[0][0]元素--//sizeof(uint16 )*100代表字节数
//把二维数组第1行100个元素拷贝给a1:
a = a + 100;//此时指针a指向a[1][0]元素--//100代表元素数
memcpy(a1,a, sizeof(uint16 )*100);
编译器在编译程序时会遵循以下原则:
(1)结构体变量中成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍)
(2)结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数。
(3)结构体大小等于最后一个成员的偏移量加上其字节大小。
如下: √ 表示结构体元素的实际偏移量,√ 之前的数表示填充,√ 之后的数表示元素占用:
typedef struct _hello
{
unsigned short b;//(2) offset:0√ 1
unsigned int c;//(4) offset:2 3 4√ 5 6 7
char a;//(1) offset:8√
//结构体大小=8+1=9,不符合:10 11 12√
}hello;
typedef struct _hello1
{
unsigned int c;//(4) offset:0√ 1 2 3
unsigned short b;//(2) offset:4√ 5
char a;//(1) offset:6√
//结构体大小=6+1=7,不符合:8√
}hello1;
typedef struct _hello2
{
char a;//(1) offset:0√
unsigned short b;//(2) offset:1 2√ 3
unsigned int c;//(4) offset:4√ 5 6 7
//结构体大小=4+4=8√
}hello2;
typedef struct _hello3
{
char a;//(1) offset:0√
unsigned short b;//(2) offset:1 2√ 3
unsigned int c;//(4) offset:4√ 5 6 7
unsigned int d;//(4) offset:8√ 9 10 11
unsigned short e;//(2) offset:12√ 13
char f;//(1) offset:14√
char g;//(1) offset:15√
unsigned short h;//(2) offset:16√ 17
unsigned int i;//(4) offset:18 19 20√ 21 22 23
//结构体大小=20+4=24√
}hello3;
void main(void) {
printf("hello = %d\n",sizeof(hello));
printf("hello1 = %d\n",sizeof(hello1));
printf("hello2 = %d\n",sizeof(hello2));
printf("hello3 = %d\n",sizeof(hello3));
}
输出结果如下:
hello = 12
hello1 = 8
hello2 = 8
hello3 = 24
@斗趣:
“ 以上回答都对,但是个人觉得非常有必要再做点补充。回调函数跟普通函数没有任何区别。只是在调用函数时略有区别。一般调用普通函数时,直接写函数名即可。但是在调用所谓“回调”函数(这个名字逼格相当的高)时,是把它(或者说它的指针)作为参数传递给另一函数。关键就在于“参数”这两个字。为什么要把某个东西参数化?只要写过一点点程序的人都知道,道理很简单,就是它存在变化的可能性。既然可以把变量做成参数,那么函数也同样可以做成参数,只要它们有变化的可能。对于一成不变的东西,显然直接嵌入便可。 ”
把函数A(的指针)作为参数传入另一个函数B,A就是回调函数。
typedef void (*funcpointer)(char*) ; //funcpointer就是我们自定义的【函数指针】类型
void callbackfunc(char* ch) //回调函数
{
static int usedtimes = 0;
usedtimes ++;
printf("%s\n",ch);
}
void directfunc(char *s,funcpointer a) //直接调用的函数
{
a(s);
printf("直接使用directfunc,directfunc通过函数指针回调callbackfunc\n");
}
void directfunc2(funcpointer a) //直接调用的函数
{
char *data = "new directfunc running";
a(data);
printf("可以用不同的函数 调用 同一个回调函数\n");
}
//main:起始函数--应用层函数:固定调用中间函数
//directfunc:中间函数--应用层函数或者库函数:通过不同的回调函数实现不同的功能
//callbackfunc:回调函数--应用层函数
int main(void) {
char *s1 ="hello world";
char *s2 ="p hello world";
directfunc(s1,callbackfunc);
directfunc(s2,&callbackfunc);//这里也证明【函数名】也是【指针】
directfunc2(callbackfunc);
directfunc2(&callbackfunc);
}
运行结果:
hello world
直接使用directfunc,directfunc通过函数指针回调callbackfunc
p hello world
直接使用directfunc,directfunc通过函数指针回调callbackfunc
new directfunc running
可以用不同的函数 调用 同一个回调函数
new directfunc running
可以用不同的函数 调用 同一个回调函数
请按任意键继续. . .
第一个函数callbackfunc:回调函数,我们写好这个函数后不会直接去调用它,只会使用它的函数指针(callbackfunc或者&callbackfunc)。
第二个函数directfunc:直接使用的函数,我们把回调函数的指针传给它,它自己去调用回调函数。
第三个函数directfunc2:直接使用的函数,我们把回调函数的指针传给它,它自己去调用回调函数。
当然,所有的函数具体要执行什么功能都是程序员自己写的。回调的好处是这两个函数可以由不同的程序员在不同的时空去写,写好了只需告知回调函数的接口就行。
typedef struct _pnode_
{
int data;
struct _pnode_ *pre;
struct _pnode_ * next;
} pnode;
int main(void) {
int i=0;
pnode *p1;
pnode *p2;
pnode *p3;
pnode *pp;
p1 = (pnode *)malloc(sizeof(pnode));
p2 = (pnode *)malloc(sizeof(pnode));
p3 = (pnode *)malloc(sizeof(pnode));
pp = (pnode *)malloc(sizeof(pnode));
p1->data = 1;
p2->data = 2;
p3->data = 3;
//p1 p2 p3
p1->next = p2;
p1->pre = p3;
p2->next = p3;
p2->pre = p2;
p3->next = p1;
p3->pre = p2;
pp = p1;
for(i=0;i<3;i++)
{
if(pp->data == 2)
{
printf("2\n");
break;
}
else
{
pp = pp->next;
printf("no 2\n");
}
}
}
打印结果
no 2
3
请按任意键继续. . .
#define WIDTH 12
#define HEIGHT 10
typedef unsigned long uint32_t;
typedef unsigned short uint16_t;
void main(void)
{
uint16_t shuzu[10][12]; //10行 12列 的数组
uint16_t X = 0;
uint16_t Y = 0;
uint16_t *ps;
uint16_t ONE[12]={1,2,3,4,5,6,7,8,9,10,11,12};
uint16_t TWO[12]={100,100,100,100,100,100,100,100,100,100,100,100};
memset(&shuzu[0][0], 0, sizeof(uint16_t)*120);
ps = &shuzu[0][0];
//方法一:memcpy,按行拷贝数据 进行赋值;
//方法二:因为二维数组地址连续,所以可用一级指针ps 进行赋值;
//方法三:直接对地址 进行赋值;
//方法四:二维数组方式 进行赋值
for(Y=0; Y<10; Y++)
{
if((Y%2) == 0)
{
//memcpy((&shuzu[0][0] + WIDTH*Y ), ONE,sizeof(uint16_t)*12);//方法一
for(X=0; X<12; X++)
{
ps[Y*WIDTH + X] =X+1;//方法二
//*(&shuzu[0][0] + WIDTH*Y + X)= X+1;//方法三
//shuzu[Y][X] = X+1;//方法四
}
}
else
{
//memcpy((&shuzu[0][0] + WIDTH*Y ), TWO,sizeof(uint16_t)*12);//方法一
for(X=0; X<12; X++)
{
ps[Y*WIDTH + X] =100;//方法二
//*(&shuzu[0][0] + WIDTH*Y + X)= 100;//方法三
//shuzu[Y][X] = 100;//方法四
}
}
}
for(Y=0; Y<10; Y++)
{
for(X=0; X<12; X++)
{
printf("%d\t",*(ps + WIDTH*Y + X));//使用方法三,进行打印输出
}
printf("\n");
}
printf("end of shuzu\n");
printf("\n");
打印结果:
1 2 3 4 5 6 7 8 9 10 11 12
100 100 100 100 100 100 100 100 100 100 100 100
1 2 3 4 5 6 7 8 9 10 11 12
100 100 100 100 100 100 100 100 100 100 100 100
1 2 3 4 5 6 7 8 9 10 11 12
100 100 100 100 100 100 100 100 100 100 100 100
1 2 3 4 5 6 7 8 9 10 11 12
100 100 100 100 100 100 100 100 100 100 100 100
1 2 3 4 5 6 7 8 9 10 11 12
100 100 100 100 100 100 100 100 100 100 100 100
end of shuzu
请按任意键继续. . .