经过1个半月的学习,差不多已经学完了c,下面是我的一些杂记,主要是指针方面,希望能够给
小白一些参考;
<stdio.h> 带着就对了
<math.h> 好像涉及数学的都要带 例如sqrt
<string.h>一类 str,
#define 提前对某个值赋值;
scanf % & 确定整数/小数/等等,然后赋值 结尾是printf(“xxx %d/f/…”,xxx);
int 假设 一般是int x,x,x…; 数字
float 单精度(带小数且较小较精确)
double 双(带。。。较大)
char 用来表示字母一般‘x’
default 剩下的
%d 整数
%f 带有小数
%c 带有英文字母
%t 相当于tab
%s 文字,英文字句
%m.nf (m指输出数据共几行,n指的是小数点占几行)
pow(x,n) 意思是x的n次方
= 赋值 ==等于
|| 并,或 (2假) && 与,且(2真)
! 非(真改为假)
x=(int)a/b 就是硬把a/b的值搞成整数 int可改为float double , 强制类型转换
********** d[i]=’\0’;//在d数组的有效字符后加‘\0’
for/while() 一个整体
{
}
double 后面的定义%lf
gets/puts(a)
sizeof 输出字节长度
****************函数的递归
我的理解就是在一个函数中继续调用这个函数
例如 int age(int n)
{int c;
if(n==1)
c=10;
else
c=age(n-1)+2; 当n=5时,age(4)+2,然后将4代入,age(3)+2+2。。。。。。。
static(静态局部变量)在函数调用结束后不消失而继续保留
auto (自动变量)可以省略
register(寄存器变量)加快运行速度
extern 扩展外部变量的作用域 见书206
内部(静态)外部函数 static extern 不能/能被其他文件调用
指针:
*************************************************************************/
//声明了一个普通变量 a
int a;
//声明一个指针变量,指向变量 a 的地址
int pa;
//通过取地址符&,获取 a 的地址,赋值给指针变量
pa = &a;
//通过间接寻址符,获取指针指向的内容
printf("%d", pa);(pa=a) 注意 输出时要带!
*****************************************************************//
**************************指向数组的指针
**如以下语句:
int nums[10], p;
1
上面语句定义了一个数组 nums,在定义时分配了 10 个连续的int 内存空间。
而一个数组的首地址即为数组名nums,或者第一个元素的首地址也是数组的首地址。
那么有两种方式让指针变量 p 指向数组 nums:
//数组名即为数组的首地址
p = nums;
//数组第一个元素的地址也是数组的首地址
p = &nums[0];
上面两句是等价的。
p + 1,此操作为指针加整数操作,即向前移动一个单元。
此时 p + 1 指向 nums[0]的下一个元素,即 nums[1]。通过p + x整数可以移动到想要操作的元素(此整数可以为负数)。
如上面,p,(p + 0)指向 nums[0]、p + 1 指向 nums[1]、、、类推可得,p+i 指向 nums[i],由此可以准确操作指定位置的元素
//由上面推导出(p + i) = nums[i],所以我们可以通过 for 循环变量元素
for(i = 0; i < 5; i++){
printf(“nums[%d] = %d”, i, *(p + i));
/公式: *(a+i)=a[i] 可以运用循环对其赋值
*(a[i]+j)=a[i][j]
*(a+i)+x=&a[i][x]=a[i]+x
p=a及p=&a[0] p++=a[0]++ 因为数组不能++,只能用指针p++
例如: 例如p=a[0],p++ 使p依次指向下一个元素 在二维数组中 a[1] *(a+1) a[1]+0表示的是1行0列的数
for(i=0;i<10;i++,p++)
printf("%d",*p)
**************int(p)[4]表示int a[4] 指针变量p指向包含4个整型元素的一维数组 通常在二维数组里运用,表示有列*指针里有4个元素
#include<stdio.h>
int main()
{
int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int (p)[4],i,j;//指针变量p指向包含4个整型元素的一维数组
p=a;//p=&a[0] 从首数组开始************************************
scanf("%d,%d",&i,&j);
printf(“a[%d,%d]=%d\n”,i,j,((a+i)+j));//a[i][j];
return 0;
}
指针字符***
chara=“love”;=chara a=“love”;
关于字符串的运用,可直接用公式*(a+i)=a[i] ,也可用*p形式。见书257
***************字符指针变量与字符数组关系:前者 存放地址,值可以改变,后者由若干个元素组成,每个元素放一个字符,并且值是固定的;
例如 char*a="i love china!";
a=a+7; 输出从a指向的字符开始的字符串;
输出结果是 china!;
可变格式输出函数;见265;
函数指针***//
int max(int,int); 函数声明;
int (*p)(int,int); 定义指向函数的指针变量p; 类型名 (*指针变量名)(函数参数表列); 就是将 函数名 改为 *指针变量名。
p=max; 使p指向max函数;
c=(*p)(a,b); 通过指针变量调用max函数;
int max(intx,inty)
在一定情况下,*p可以指向多个函数:
n==1 p=max
n==2 p=min c=(*p)(a,b)
if(n==1)输出c max
else 还是输出c min 见269;
指向函数的指针作函数参数;
int fun(int x,int y,int(*p)(int,int))
int max/min/add(int,int); 注意不能p=max/。。。。。。
…
fun(a,b,max/min/add);
…
…
int max()
…
int min()
…
iny add()
…
*****返回指针值的函数 类型名 *函数名(参数表列); float *xxx( )
- 用函数指针作为函数的返回值
在上面提到的指针函数里面,有这样一类函数,它们也返回指针型数据(地址),但是这个指针不是指向int、char之类的基本类型,
而是指向函数。对于初学者,别说写出这样的函数声明,就是看到这样的写法也是一头雾水。比如,下面的语句:
int (*ff(int))(int *, int);
我们用上面介绍的方法分析一下,ff首先与后面的“()”结合,即:
int (*(ff(int)))(int *, int); // 用括号将ff(int)再括起来
也就意味着,ff是一个函数。
接着与前面的“*”结合,说明ff函数的返回值是一个指针。然后再与后面的“()”结合,也就是说,该指针指向的是一个函数。
这种写法确实让人非常难懂,以至于一些初学者产生误解,认为写出别人看不懂的代码才能显示自己水平高。而事实上恰好相反,
能否写出通俗易懂的代码是衡量程序员是否优秀的标准。一般来说,用typedef关键字会使该声明更简单易懂。在前面我们已经见过:
int (*PF)(int *, int);
也就是说,PF是一个函数指针“变量”。当使用typedef声明后,则PF就成为了一个函数指针“类型”,即:
typedef int (*PF)(int *, int);
这样就定义了返回值的类型。然后,再用PF作为返回值来声明函数:
PF ff(int);
指针数组和多重指针***/ 类型名 *数组名 [数组长度];int *p[4] //注意不是int (*p)[4]这是指向一维数组的指针变量
比较适合指向若干个字符串 就是数组前加个*而已
int a[2][3]={{1,4,6},{12,4,7}};
int *p[2]; 指针数组p[2]指向a数组的2个地址
p[0]=&a[0];//&a[0][0] 起始 p[1]=&a[1];//&a[1][0]
printf("%d\n",(p[0]+1)); //a[0][1] printf("%d\n",(p[1]+2)); //a[1][2]
**********************************数据类型 *q///类型名**指针变量名
int * *q 两个指针 一般当前面有个指针,且下面还要用道指针指向这个指针时
#include<stdio.h>
int main()
{
char name[]={“follow”,“basic”,“great”,“for”,“com”}; 注意: int a[5]={1,2,3,4,5};
charp; int num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]}; //因为指针数组的元素只能存放地址.
int i; 不能是 intname[5]={1,2,3,4,5};
for(i=0;i<5;i++)
{
p=name+i; //指针p要指向指针数组name.
printf("%s\n",p); 输出指针数组一个 intp intq[2] int a[3]
} **p —> *q[0] —> 3 q[0]=&a[0] q[1]=&a[1]…
return 0; **(p+1) —> *q[1] —> 6 p=q//p=&q[0] 指向首地址
} 9
用指针数组作main函数的形参 int main(int argc, char *argv[]) 在dev里作项目;
动态内存分配与指向它的指针变量
开辟动态存储区 #include<stdlib.h>
malloc voidmalloc(unsigned int size); 在内存的动态存储区分配一个长度为size的连续空间 malloc(100) a=(int )malloc(nsizeof(int)) 将nsizeof(int)个内存给a
calloc void*calloc(unsigned n,unsigned size); 在内存的动态存储区分配n个长度为size的连续空间 p=calloc(50,4) 50x4个字节的临时分配域;
relloc voidrelloc(voidp,unsigned int size); 重新分配动态存储区; relloc(p,50) 将p所指向的已分配的动态空间改为50字节;
free void free(void*p); 释放动态存储区 free(p)释放指针p所指向的已分配的动态空间;
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct student
{
char *name; //改 char name [];
int score;
}*pstu;
int main()
{
pstu=(struct student*)malloc(sizeof(struct student)); ///将地址转成struct student* 型
改:char *p=NULL;
strcpy(pstu->name,"tom");
pstu->score=99;
改:char *p=NULL;
printf("name =%s,score =%d\n",pstu->name,pstu->score);
free(p);
return 0;
}
原式是一个野指针问题,为了避免出现野指针,通常我们需要将指针初始化为NULL,用完后也为其赋值为NULL。
结构体成员指针往往会被我们忽视,注意它也需要初始化,且需要为结构体指针分配足够的内存,真是就用到了malloc这个宏,使用方法如下:
给指针变量赋初值:
方法一:char * p = (char * )malloc(sizeof(char));
方法二:char * p = NULL;
给数组赋初值:
方法一: int a[10] = {0};
方法二: memset(a, 0, sizeof(a));
memset函数有3个参数:第一个是要被设置的内存起始地址;第二个是要被设置的值;第三个是要被设置的内存大小,单位为字节;
给结构体指针赋初值:
方法一: pstu = (struct student *)malloc(sizeof(struct student));
常见错误: pstu = (struct student *)malloc(sizeof(struct student *));
使用完指针后务必记得释放指针所指向的内存,否则不知道什么时候我们又改变了指针的值,使其变成了野指针!
这里就需要free§这个函数的帮忙了,它可以切断指针与指向内存的联系。但是需要注意的是free对于同一指针变量只能使用一次。不然会导致出错或者内存泄漏。
释放完内存后另指针的值变为NULL!
如下:
free§;
p = NULL;
结构体指针/// 例如struct student*pt //pt可以指向struct student类型的变量或数组元素
struct xxxxxa
{
xxxx
xxxx
xxxx
};
struct xxxxa t;
struct xxxxa *p;
p=&t;
下面用t.xxxx
…
…
…
printf("…",(*P).xxxx,(*P)xxxx…)
void指针*
void*指针变量
在输出时要强制转换类型 一般是printf("%d",p) 如果是void 则 printf("%d",(int *)p);
#include<stdio.h>
int main()
{
int a[]={1,2,3,4,5}; const变量 常量化变量的值 固定一个变量的值
int i,n;
void p; const <数据类型> 变量名=[表达式]
const <数据类型><指针变量名称>[=<指针变量表达式>]
p=a;
n=sizeof(a)/sizeof(int); <数据类型>const<指针变量名>[=<指针运算表达式>]
for(i=0;i<n;i++)
printf("%d",((int *)p+i); 结尾要强制转换
puts("");
return 0;
}
#include<stdio.h>
int main()
{
int a[]={1,2,3,4,5};
int i,n;
void *p;
int *q;
p=a;
q=(int )p; 或者中途转换
n=sizeof(a)/sizeof(int);
for(i=0;i<n;i++)
printf("%d",(q+i);
puts("");
return 0;
}
***共用体,枚举
我的理解 :共用体放在结构体中; 枚举 就是把可能的值一一列出来,变量的值只限于列举出来的值; union 共用体名 enum 枚举名 {枚举元素列表}
struct xxx enum color{red,yellow,blue,white,black}; 定义枚举类型
{ enum color i,j,k,pri; 定义枚举变量;变量只能在类型里运用;
xxx …
xxx
union
{
xxxx
…
};
};
用typedef声明新类型名 typedef int real ;//指定real为类型名,作用与int相同;