指针,字符,字符串,函数指针,总结

指针即为地址,指针几个字节跟语言无关,而是跟系统的寻址能力有关。譬如以前是16为地址,指针即为2个字节,现在一般是32位系统,所以是4个字节,以后64位,则就为8个字节。

指针运算符:

1.算数运算:指针±整数;  加就是右移一个类型长度字节,反之亦然,int就移动4个字节,char就移动1个字节。

2.指针运算:指针-指针=内存中的距离,该距离的单位是类型长度单位;并且必须相对于同一数组而言

3.关系运算:指针≥ ≤ >< = 指针,必须相对于同一数组而言

1.整型

整型初始化 int a1 = 100;

负数初始化 int a2 = -2;

指针赋值 int *a3 = &a1; note:这种方式会让人感觉是把a1的地址传给了 *a3,其实是传的值是a3,好一点的写法,int *a3=NULL; a3 = &a1;

数组初始化 int a3[5] = {0} ; int a3[5] = {1,2,3,4,5};其中的a3是数组a3的起始地址;printf("a3 = %p",a3)可以打出a3的地址,用*a3可以打出数组a3第一个值a3[0].printf("a3=%p", &a3)的值就是a3的地址

对于 int a4[5] = {1,2,3}, 实际长度比赋值的数目多,对于没有初始化的位置,则默认初始化为0,对于 int a5[] = {1,2,3,4};能自动的分配数组长度,这种方式比较可靠

注意a3+3,不是a3的地址右移动3个字节,而是3个int长度的位置。实际是到a[4]这个地址

二重指针 int **a4 = &a3, 把指针a3的地址取出来,赋值给a4, **表示变量 a4里面存的是一个地址,这个地址指向的内容,又是另一个地址,所以 *a4是a3地址里面的值。

2.字符,字符数组,字符指针,字符串

1.字符

char在内存中占一个字节,8个比特位,无符号的范围是0-255,unsigned char 范围-127~127

字符初始化:char a = 'a'; ,赋值:a= 'c'; 同样可以 &a取出其地址。

2.字符数组

字符数组初始化:char temp[6] = {0},temp的6个位置都填'\0'字符; char temp[] = {'a', 'b', 'c', 'd'};char temp[5] = {'a', 'b', 'c', 'd'}或者 这种方式较冗余,对于 char temp[10] = {'a', 'b', 'c', 'd'},则实际只用了4位,打印出来还是abcd.

char temp1[]="abcd";这种方式比较方便,也能动态分配数组长度。

字符数组的整体赋值只能在字符数组初始化时使用,不能用于字符数组的赋值,字符数组的赋值只能对其元素逐个赋值

char str[ ];
str="I am happy";//错误,字符数组的赋值只能按元素一一赋值

用两种不同方法初始化字符数组后得到的数组长度是不同的

#include <stdio.h>
void main(void)
{
char c1[]={'I',' ','a','m',' ','h','a','p','p','y'};
char c2[]="I am happy";  //后面会添加/0所以长度是11
char C3[100] = "abcde";  //以最长的长度为准
int i1=sizeof(c1); 
int i2=sizeof(c2); 
int i3=sizeof(c3);
printf("%d\n",i1);
printf("%d\n",i2);
printf("%d\n",i3);

}

结果:10, 11 , 100

字符数组本质也是数组,因此可以适用: 算数运算,指针运算,关系运算。

strcpy(char *dst, char *src);也可以传入 temp和 temp1因为这两个也是地址。

3.字符指针

字符指针初始化:char *a = NULL; char b* = "abcd";

字符指针赋值:a= "12345" , b= "hello", 可以通过指针指向字符串的方式进行指针赋值。

注意字符数组不能这样赋值:char m[8] = {0}; m = "12345678";

4.结构体

1.结构体定义

struct test {

        char[8] name;

        int age;

};

typedef struct test TEST;

则声明就只用,TEST t5;

2.结构体声明和初始化

struct test t1; //还未初始化,只是声明

strcpy(t1.name, "abc"); //赋值

t1.age = 10; //赋值

结构体初始化:

不指定初始化的项目

struct test t2 = {

"abc",

100

};

指定初始化的项目

struct test t3 ={

.name = "ABC",

.age = 100

};

简化声明:

struct book{

char name[8];

char auth[8];

} book1;直接简化声明book1,能够使用了。

可以用

typedef strcuct class{ 

int class_num;

char member[56];

} CLASS;

这样就可以简洁方便的定义结构体 CLASS,直接

CLASS class1; 等价于 struct class class1。

3.结构体指针

struct book *b; //声明

b = &book1; //赋值

printf("b->name is %s", b->name); //指针取值要用 -> 符号

printf("b->age is %s", b->auth); 

1.结构体嵌套

struct student{

char name[8];

int age;

};

struct class{

int num;

struct student  st1;

struct strudent *t2;

} cc1;

对于st1的取值,应该是,cc1.st1.age 和cc1.st1.name

对于st2的取值,应该是,cc1.st2->age 和cc1.st2->name;

因为 t2是指针,所以要用 ->取值。对于用  .  还是  ->  要看当前结构体的类型是否是指针。比如cc1不是指针,所以用 .  取值,而st2是指针,则要用  ->  。

2.结构体数组

6.malloc和free

1.malloc()

malloc()找到可用内存中一个大小适合的块。
malloc分配的内存是匿名的,也就是说,malloc()分配了内存,但没有为它指定名字。
然而,它却可以返回那块内存第一个字节的地址。
因此,可以把那个地址赋值给一个指针变量,并使用该指针来访问那块内存。
因为char代表一个字节,所以传统上曾将malloc()定义为指向char的指针类型。

然而,ANSIC标准使用了一个新类型:指向void的指针。这一类型被用作“通用指针”。
函数malloc()可用来返回数组指针、结构指针等等,因此一般需要把返回值的类型指派为适当的类型。

在ANSIC中,为了程序清晰应对指针进行类型指派,但将void 指针值赋值给其他类型的指针并不构成类型冲突。
如果malloc()找不到所需的空间,它将返回空指针。
我们使用malloc()来创建一个 数组。可以在程序运行时使用malloc()请求一个存储块,另外还需要一个指针来存放该块在内存中的位置。

double * ptd;
ptd = (double * ) malloc (30 * sizeof(double));

这段代码请求30个double类型值的空间,并且把ptd指向该空间所在位置。

此时可以将指针转换成数组,ptd[0],ptd[1].....ptd[29]分别对应每个元素

记住:数组的名字是它第一个元素的地址。
因此,如果令ptd指向一个内存块的第一个元素,就可以像使用数组名一样使用它。
也就是说,可以使用表达式ptd[0]来访问内存块的第一个元素,pd[1]来访问第二个元素,依此类推。
正如前面所学,可以在指针符号中使用数组名,也可以在数组符号中使用指针。

使用第二种或第三种方法可以做一些用普通的数组声明做不到的事:
创建一个动态数组(dynamic array),即一个在程序运行时才分配内存并可在程序运行时选择大小的数组。
例如,假定n是一个整数量。在C99之前,不能这样做:

double item[n]:/*如果n是一个变量,C99之前不允许这样做*/

然而,即使在C99之前的编译器中,也可以这样做:

ptd =(double*)malloc(n*sizeof(double));/*可以*/

这行得通,而且正如您将看到的那样,这样做比使用一个变长数组更灵活。

一般地,对应每个malloc()调用,应该调用一次free()。
函数free()的参数是先前malloc()返问的地址,它释放先前分配的内存。

这样,所分配内存的持续时间从调用malloc()分配内存开始,到调用free()释放内存以供再使用为止。

设想malloc()和free()管理着一个内存池。
每次调用malloc()分配内存给程序使用,每次调用free()将内存归还到池中,使内存可被再次使用。
注意:free()的参数应是一指针,指向由malloc()分配的内存块;
其他方式(例如声明一个数组)分配的内存是不能使用free()去释放的。

malloc结构体举例

struct student
{
int num;
char name[8];
};

struct student *s1 = NULL; /*注意写法*/
s1 = (struct student*)malloc(sizeof(struct student)); /*注意写法*/

2.free ( )

在编译程序时,静态变量的数量是固定的:在程序运行时也不改变。

自动变量使用的内存数量在程序执行时自动增加或者减少。
但被分配的内存所使用内存数量只会增加,除非您记得使用free()。

例如,假定有一个如下代码勾勒出的函数,它创建一个数组的临时拷贝:

#include<stdio.h>
#include<malloc.h>

void gobble (double ar[], int n);

int main(){
	double glad[2000];
	int i;
	
	for(i = 0; i<100000000; i++){
		gobble(glad, 2000);
	}
}

void gobble(double ar[], int n){
	double *temp = (double *) malloc(n*sizeof(double)) ;
	
//	free(temp);/*忘记使用*/
}

第一次调用gobble()时,它创建了指针temp,并使用malloc()为之分配16000字节的内存(设double是8个字节)。
假定我们如暗示的那样没有使用free()。
当函数终止时,指针temp作为一个自动变量消失了。
但它所指向的16000个字节的内存仍旧存在。
我们无法访问这些内存,因为地址不见了。
由于没有调用free(),不可以再使用它了。
第二次调用gobble(),它又创建了一个temp,再次使用malloc()分配16000个字节的内存。
第一个16000字节的块已不可用,因此malloc()不得不再找一个l6000字节的块。
当函数终止时,这个内存块也无法访问,不可再利用。
但循环执行了1000次,因此在循环最终结束时,已经有1600万字节的内存从内存池中移走。
事实上,在到达这一步前,程序很可能已经内存溢出了。

这类问题被称为内存泄漏(memory leak),可以通过在函数末尾处调用free()防止该问题出现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值