1.常混概念:
int *p[10]是指针数组,你看呀,把他当做一般指针定义的形式呀:int * ( p[10] )
int (*p)[10]是数组指针,显然嘛,*p是个指针,指向数组。
你造吗?[]优先级是最高的!!!!!!!!!([],.,->是优先级较高的)
2.函数指针:
(1).函数编译后得到的二进制程序放在一段连续内存中,编译器吧这段首地址与函数名绑定。存有这个地址的变量就是函数指针么。
(2).有个函数void func(void);
int main(void)
{
void (*pFunc)(void); //类型,参数要相同;;;;;其实把(*pFunc)看做func就行
pFunc=func; //绑定
//pFunc=&func; //和数组不一样,这样也可行
pFunc(); //调用
return 0;
}
补充: strcpy函数(char *strcpy(char *dest, const char *src);),对应的函数指针是:char *(*pFunc)(char *dest, const char *src)。
typedef void (*pFunc)(void); //这定义了一个新类型,类型名叫pFunc,类型为void (*)(void);用的时候pFunc p1;p1=func。
(3).利用函数指针可以调用不同函数,这就是面向对象中的多态本质。写一个类似计算器程序,实现调用不同函数。
(4)分层次写代码,不同层次间用头文件交互;
上层注重业务逻辑,写用于实现的函数以及定义相关变量给下层调用;
下层注重为上层填充变量,并且将变量传递给上层中的函数(其实就是调用上层提供的接口函数)来完成任务;
下层代码中其实核心是一个结构体变量(譬如本例中的example),写下层代码的逻辑其实很简单:第一步先定义结构体变量;第二步填充结构体变量;第三步调用上层写好的接口函数,把结构体变量传给它既可。
错误点:把换行符斜杠写反;
scanf格式和printf格式差不多,中间是逗号,不是分号;
中英文又没分清;
定义结构体里面是分号隔开, 用linux内核风格定义结构体变量里面是分号,最后都是有分号结束的;(struct A a={b=1,c=2,};)
使用别人文件的东西,麻烦用他的头文件给他说一下,别跟小偷一样;
写头文件前#ifndef __XXX_H__ #define__XXX_H__ #endif 拜托写完。
整体代码:
#include<stdio.h>
int add(int a,int b);
int minus(int a,int b);
int multiply(int a,int b);
int divide(int a,int b);
typedef int (*pFunc)(int,int);
int main(void )
{
int a=0,b=0;
char c=0;
pFunc p1;
printf("enter number:\n");
scanf("%d %d",&a,&b);
printf("enter signal:+ 、-、*、/\n");
/*
getchar();
scanf("%c",&c);
*/
do
{
scanf("%c", &c);
}while (c == '\n');
switch(c)
{
case '+':
p1=add; break;
case '-':
p1=minus; break;
case '*':
p1=multiply; break;
case '/':
p1=divide; break;
default:
printf("3请输入指定运算符号,本次结束运行\n");break;
}
printf("the result is %d\n",p1(a,b));
return 0;
}
int add(int a,int b)
{
return a+b;
}
int minus(int a,int b)
{
return a-b;
}
int multiply(int a,int b)
{
return a*b;
}
int divide(int a,int b)
{
return a/b;
}
我们来分层次写:
有三个文件:
cal.h
#ifndef __CAL_H__
#define __CAL_H__
typedef int (*pFunc)(int ,int );
struct set_para
{
int a;
int b;
pFunc p;
};
int add(int a,int b);
int minus(int a,int b);
int multiply(int a,int b);
int divide(int a,int b);
void calculator (struct set_para *p1);
#endif
#include "cal.h"
void calculator (struct set_para *p1)
{
int res=p1->p(p1->a,p1->b);
printf("resuilt is %d\n",res);
}
int add(int a,int b)
{
return a+b;
}
int minus(int a,int b)
{
return a-b;
}
int multiply(int a ,int b)
{
return a*b;
}
int divide(int a,int b)
{
return a/b;
}
cal.c
#include<stdio.h>
#include "cal.h"
int main(void)
{
struct set_para example=
{
.a=12,
.b=4,
.p=divide,
};
calculator(&example);
return 0;
}
写函数获得:
第一:当程序出现段错误时,第一步先定位段错误。定位的方法就是在可疑处加打印信息,从而锁定导致段错误的语句,然后集中分析这句为什么会段错误。
第二:linux中命令行默认是行缓冲的,将其缓冲起来放在缓冲区等一行准备完了再一次性把一行全部输出出来(为了效率)。linux判断一行有没有完的依据就是换行符'\n'(windows中换行符是\r\n,linux中是\n,iOS中是\r)。也就是说你printf再多,只要没有遇到\n(或者程序终止,或者缓冲区满)都不会输出而会不断缓冲,这时候你是看不到内容输出的。因此,在每个printf打印语句(尤其是用来做调试的printf语句)后面一定要加\n,否则可能导致误判。
第三:我 们用户在输入内容时结尾都会以\n结尾,但是程序中scanf的时候都不会去接收最后的\n,导致这个回车符还存留在标准输入中。下次再scanf时就会先被拿出来,这就导致你真正想拿的那个数反而没机会拿,导致错误。解决方法:用getchar()拿掉或者在scanf前加一个while(c =='/n')
第四:很多玩意不写真的用不熟,老是错,宛如一个zz.
3.typedef解析:
1).定义结构体的两种方式:
第一种:
struct program_monkey
{
int age;
char name[20];
int wages;
}m0; //m0是个变量,不是重命名
struct program_monkey m1;
struct program_monkey *m2;
第二种:
typedef struct program_monkey
{
int age;
char name[20];
int wages;
}pm,*pPm;
pm p1;
pPm p2; //p2为指针变量
2).typedef绝不是单纯的替换,而是新定义一种类型,这和define是不同的(另外顺序不同,也要加上分号)。两个例子:
第一个:
typedef int * int_p;
int_p p1,p2; //p1,p2都是指针
int* p3,p4; //p3是指针,p4是普通变量
第二个:
typedef int * int_p;
const int_p p1; //这里的指针p1是const,不可改变。
补充:typedef 的两种用途:简化;
定义与平台无关的类型;例如typedef int size_t;这样当平台迁移,int位数改变,可以只用改一句话就行了。
4.指针有数组指针,函数指针,二重指针(一般和数组指针一起用:int *a[10];int **p;p=a;另外在函数传参时,一重指针可以改他指向的变量,二重指针才能改一重指针的值),
结构体指针等这些类型,本来是不需要的,但是设计这些类型是为了在编译时编译器帮你做静态类型检查,避免类型不匹配。
5.二维数组:
1).其与一维数组在存储上是一模一样的,在效率上的差异也可忽略不计,外层是一维,内层是二维。
2).指针访问:
int a[4][5];
//int *p=a; //类型不匹配
int (*p1)[5]=a; //p1是数组指针,这里的a和&a[0]相同;辣么*(*(a+i)+j),*(*(p1+i)+j)表示a[i][j];
int *p2=a[0] //p2指向一个一维数组,这里的a[0]和&a[0][0]相同;*(p2+4)表示a[0][4];靠p2访问不到a[1].