一、野指针的概念
野指针:就是指向你确定址的指针
野指针产生的原因:
定义的指针变量没有被初始化
堆上申请的内存被释放后没有赋值为NULL
二、const关键字修饰指针变量
常量指针:const int *p;约束指针指向的值不能被修改
int const *p;
指针常量:int * const p;约束指针变量本身不能被修改,但是指向值可以被修改。
三、数组与字符指针
引用一个字符:字符数组,字符指针
char ch[10] = "sdfsdf";
char ch1[4][4] = {"sdfasa","asdafsd",...};
ch = "sdasfd"; //是错误的,因为数组名是一个指针常量
char *s = "asdasf";
s[0] = 'a';// s是错的
四、指向函数的指针
1)定义:指向函数的入口地址,函数名本身就是一个地址
函数的返回类型(*函数指针名)(形参列表);
double (*fun)(int,int); //定义一个名为fun的函数指针,它指向一个函数返回double类型并且接收两个整形参数。
2)用途:1、通过函数的指针调用函数
fun = add;
(*fun)(10,20); // add(10,20);
//fun(10,20);
2、用函数指针做为参数
typedef double (*myfun)(int,int); //typedef double (*fun)(int,int) myfun
void test(myfun f,int n)
{
f();
}
typedef 已存在的类型 新类型;
typedef double mydouble;
五、指针函数(函数的返回值是一个指针类型)
int * add(int a,int b)
{
static int c=0;
c = a + b;
return &c;
}
void add(int *a,int b) //利用函数的指针类型的形参将函数的处理结果值带回到主调函数中
{
a[0] = 11;
a[2] = 33;
a[0] = b+1;
}
int main()
{
int arr[3] = {0};
add(arr,3);
printf(arr[0]);
}
函数返回多个值:
1)建立全局变量
2)利用指针函数
int * add(int a,int b)
{
static int arr[3];
arr[0] = 100;
return arr;
}
3)利用指针做为形参的多个值得返回
六、空指针
1)定义:int * p = NULL; //不指向任何的地址;
NULL == ((void *) 0)
作用:状态的比较,避免指针的非法引用
七、无类型指针
1)定义无类型指针:void *pd; //无类型指针它是有值得,但是它指向的区域是没有类型,失去了加1能力不能对无类型指针进行解引用 *pd
2)无类型指针可以接收其他类型指针的赋值
3)无类型指针转转为其他类型的指针,需要做强制类型转换
void *pd = &a;
char * p =(char *)pd;
4)多用于函数的形参,用来接收任意类型的指针
结构体:
定义:
为了定义结构,您必须使用 struct 语句。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:
#include <stdio.h> #include <string> struct student { char name; short int age; short int score; }; int mian() { struct student stu1; stu1.age = 12; strcpy(stu1.name,"XiaoMin"); return 0; }
引用结构体变量
结构体变量名.成员变量
其中“.”为结构体成员运算符,它的优先级最高。结构体变量中没一个成员和普通变量一样,可以进行各种运算。
定义结构体后,可以引用这个变量,但应遵循以下规则:
1)同类型的结构体变量可以互相赋值,但不能将一个结构体变量作为一个整体进行输入和输出。
2)如果成员本身又属于一个结构体,则要用若干个成员运算符,一级一级的找到最低级的成员,进行赋值或存取及运算。
3)对结构体变量的成员可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)。
4)可以引用结构体变量成员的地址,也可以引用结构体变量的地址如:
scanf(″%d″,&student1.num); //为成员student1.num赋值 printf(″%o″,&student1); //输出变量student1的首地址
结构体变量的初始化:
和其它类型变量一样,对结构体变量可以在定义时指定初始值。
#include <stdio.h> struct student { char name[20]; int age; } int main() { struct student stu[] = {{"xiaoming",21},{"xiaowang",25}}; //结构体变量初始化 printf("name=%s\tage=%d\t\n",stu[0].name,stu[0].age); //打印结构体中的数据 }
结构体数组
结构体数组与整形数组、实型数组、字符型数组一样,在程序中也可以定义结构体类型的数组,并且同一个结构体数组中的元素应为同一种结构体类型。
struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; };stu[3]; /*直接定义结构体数组*/ struct student stu[3];
结构体数组的初始化:
与其它类型的数组一样,对结构体数组可以初始化。例如:
struct student { int num;char name[20]; char sex; int age; float score; char addr[30]; }stu[3]={{10101,″LiLin″,′M′,18,87.5,″103 BeijingRoad″}, {10102,″Zhang Fun″,′M′,19,99,″130 Shanghai Road″}, {10104 ,″Wang Min″,′F′,20,78.5 ,″1010 Zhongshan Road″} };
结构体指针
结构体类型的指针变量指向结构体变量或数组(或数组元素)的起始地址。
例如:
struct student { int num; char name[10]; char sex; int age; float score; }; struct student stu1,stu2,st[10],*p;
当结构体类型的指针变量p指向一个结构体类型变量后,下列三种表示是等价的:
注意:当p定义为指向结构体类型的变量后,它不能指向某一成员。
例如, p = &stu1.num; //是错误的,因为它企图让结构体指针变量指向函数体变量stu1中的成员num。
字节对齐问题
对齐概念:计算机中内存空间都是按照字节byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。如果一个变量的内存地址正好位于它长度的整数倍,被称做自然对齐。
字节对齐设计到的四个重要的基本概念:
1)数据类型自身的对齐值:
对于char型数组,其自身对齐值为1,对于short型为2.对于int,float等类型,其自身对齐值为4,单位字节。
2)结构体自身对齐值:其成员中自身对齐值最大的那个值。
3)对指定对齐值
4)有效对齐值:自身对齐值和指定对齐值中小的那个值
字节对齐规则:
1)成员按照自身的对齐值对齐:如果不在对齐边界,编译器会在加上填充字节。
2)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节。