数据结构1 C语言关于指针,结构体,动态内存。


郝斌老师——心中永远的神!

I 指针

1 什么是指针

#include<stdio.h>
int main(void)
{
    
    
int *p;   //p是一个指针变量的名字, int* 表示该p变量只能储存int类型的地址,
		  //地址就是内存单元的编号,cpu可以直接访问内存,
		  //通过三根线:cpu——[地址线(访问内存编号),控制线(读还是写),数据线(传输数据)≡]——内存 
		  //地址:内存单元的编号 是从0开始的非负整数 范围(0~4G-1)
		  //指针:指针就是地址,地址就是指针。指针变量是存放内存单元地址的变量
		  //指针的本质是一个操作受限的非负整数
		  

int i = 10;
int j;

p = &i;
printf("%d\n",*p);
return 0;
}

2 空指针

#include<stdio.h>
int main(void)
{
    
    
int *p;   
int i = 10;
int j;

j = *p;  //p里面没有保存一个变量的地址,所以不能赋值
printf("%d\n",j);

return 0;
}——》崩溃

3 指针的使用

#include<stdio.h>
int main(void)
{
    
    
int *p;  
int i = 10;
int j;

p = &i;  //把i的地址发送给P  p就指向了i   修改p的值不改变i的值,
         //修改i的值也不改变p的值 
         //告诉我*p是谁? 回答是:i变量   *p就代表了i 他俩是一个东西
//int* p = i; 等价于 int *p; p = &i;
printf("%d\n",*p);

j = *p;  //等价于 j = i;
printf("%d\n",j);

return 0;
}——》10 10

4 局部变量问题:如何通过被调函数修改主函数中变量的值

void f(int* p)
{
    
    
	*p = 100;
}
#include<stdio.h>
int main(void)
{
    
    
	int i = 9;
	
	f(&i); //值传递 把i的地址值传递过去 *p = 100 就相当于 i = 100 重新对i赋值了
	printf("%d\n",i);

return 0;
}——》100

如果不用上面方法:

void f(int p)
{
    
    
	p = 100;
}
#include<stdio.h>
int main(void)
{
    
    
	int i = 9;
	
	f(i); //值传递 9 = 100; 不会造成任何影响
	printf("%d\n",i);

return 0;
}——》9

5 用被调函数改变主调函数中变量的地址

void f(int* p)
{
    
    
	*p = 99;
}
#include<stdio.h>
int main(void)
{
    
     
	int i = 10;
	int* p = &i;
	printf("%d\n",i);
	printf("%p\n",p);	
	f(&i);
	printf("%d\n",i);
	printf("%p\n",p);
	
	
	return 0;
}——》10 0019FF2C 99 0019FF2C
 ——》可以看到这样操作并没有改变该变量所在地址
 ——》那么如何改变变量的地址呢
void f(int** q) //既然我们要修改变量的地址,那我们传进来的就是
				//变量自身对应的地址变量的地址
				//那么我们现在再从这个逻辑中抽身出来,如何通过被调函数
				//修改主函数中普通变量的值 —— 上面自然已经说清了				 
{
    
    		
	*q = (int*)0xFFFFFFFF;
}
#include<stdio.h>
int main(void)
{
    
     
	int i = 10;
	int* p = &i;
	printf("%d\n",i);
	printf("%p\n",p);	
	f(&p);            //函数的参数是地址的地址
	printf("%d\n",i);
	printf("%p\n",p);
	
	
	return 0;
}——》10 0019FF2C 10 FFFFFFFF  被改变了

6 指针和数组


#include<stdio.h>
int main(void)
{
    
       						//一维数组的各个元素的地址是连续的(步长)
	int a[5] = {
    
    1,2,3,4,5}; //一维数组名是个指针常量,
							//他存放的是一维数组第一个元素的地址,
						    //他的值不能被改变,
							//一维数组名(这个指针)指向的是数组的第一个元素
						    //a[i] 等价于 *(a+i)
	
	printf("%p\n",a);
	printf("%p\n",a+1);
	printf("%p\n",a+2);
	printf("%p\n",a+3);
	printf("%p\n",a+4);
    
	//ps:看这个 他等价于 a[0]+3 
    printf("%d\n",*a+3);  !!+3在严格意义上讲是+(3*相应步长) int 步长为4 
return 0;
}——》0019FF1C 0019FF20 0019FF24 0019FF28 0019FF2C  4

7 局部变量问题(数组)


void Show_Array(int* p)
{
    
    
	p[0] = -1; // p[0]等价于*p
	p[2] = -2; // p[2]等价于*(p+2)
}
#include<stdio.h>
int main(void)
{
    
     
	int a[5] = {
    
    1,2,3,4,5}; 
	Show_Array(a); //值传递 把数组的首地址传过去了 相当于重新赋值
	printf("%d\n",a[0]);
	printf("%d\n",a[2]);					
return 0;
}——》-1  -2  

8 用函数输出数组

void Show_Array(int* p ,int len)
{
    
       
	int i = 0;
	for(i=0; i<len; i=i+1)
	{
    
    
		printf("%d\n",p[i]);
	}

}
#include<stdio.h>
int main(void)
{
    
     
	int a[5] = {
    
    1,2,3,4,5}; 
	Show_Array(a,5);				
	return 0;
}——》1 2 3 4 5

9 无论指针指向的谁,指针变量本身只占四个字节

#include<stdio.h>
int main(void)
{
    
     
	double* p;
	double  x = 66.6;
	
	p = &x; //x占8个字节, 一个字节是8位,一个字节一个地址。
	printf("%p\n",p);
	
	double arr[3] = {
    
    1.1,2.2,3.3};
	double* q;
	
	q = &arr[0];
	printf("%p\n",q); //%p其实就是以十六进制输出
	q = &arr[1];
	printf("%p\n",q);
	
	return 0;
}——》0019FF24  0019FF0C 0019FF14  0C(12) + 8 = 14(20) 
               浮点数是八个字节就间隔了八个地址(氦 就是一个步长是八字节嘛)

II 结构体

结构体
为什么会出现结构体:面向对象语言中包含类的概念:类包含属性和方法。而结构体没有方法
属性也不叫属性,而是叫成员。

结构体是用户根据实际需要自己定义的复合数据类型。结构体不是变量,而是数据类型。变量
在定义的时候是需要分配内存的。

结构体变量不可以加减乘除,但是可以相互赋值

1 “.”访问结构体

#include<stdio.h>
#include<string.h>
struct Student
{
    
    
	int sid;
	char name[200];
	int age;
}; //这个分号是不能省略的
int main(void)
{
    
     
	struct Student st1 = {
    
    1000,"yunduo",20};
//对成员重新赋值
	st1.sid = 9999;
	//st1.name = "liyunduo";  //error
	strcpy(st1.name,"liyunduo");
	st1.age = 21;
	
	printf("%d\n",st1.sid);
	printf("%s\n",st1.name);
	printf("%d\n",st1.age);
	
	return 0;
}——》1000 yunduo 20

2 “地址”访问结构体

#include<stdio.h>
#include<string.h>
struct Student
{
    
    
	int sid;
	char name[200];
	int age;
}; 
int main(void)
{
    
       
	struct Student st1 = {
    
    1000,"yunduo",20};
	struct Student* adrst2 = &st1;

	adrst2 -> sid = 888; // adrst2 -> sid 等价于 (*adrst2).sid
	//这句话:表示adrst2所指向结构体变量中的这个 —》sid成员《— 
	strcpy(adrst2 -> name,"windoo");
	adrst2 -> age = 18;

	printf("%d\n",adrst2 -> sid);
	printf("%s\n",adrst2 -> name);
	printf("%d\n",adrst2 -> age);
	
	return 0;
}——》888 windoo 18

3 通过被调函数更改主调函数中定义结构体的成员值

#include<stdio.h>
#include<string.h>
struct Student
{
    
    
	int sid;
	char name[200];
	int age;
}; 
void f(struct Student* adrstx)
{
    
    
	adrstx -> sid = 88;  //或 (*pst).sid = 90;
	strcpy(adrstx -> name,"888");
	adrstx -> age =8888;
}
void f1(struct Student*  adrst) //读取时候也要用指针,占内存少,快速。
{
    
    
	printf("%d\n",adrst -> sid);
	printf("%s\n",adrst -> name);
	printf("%d\n",adrst -> age);
}
int main(void)
{
    
       
	struct Student st;
	struct Student* adrst2 = &st;

 	f(adrst2);
	
	f1(adrst2);


	
	return 0;
} ——》88 888 8888

III 内存

1 动态内存分配malloc

#include<stdio.h>
#include<malloc.h>
int main(void)
{
    
    
	int len;
	int a[5] = {
    
    4,10,2,8,6}; //静态数组,数组的长度是死的,通过下标访问元素。
	printf("请输入你需要的数组的长度 len = ");
	scanf("%d",&len);
	int* pArr = (int* )malloc(sizeof(int) * len);
	//malloc:获取x字节的可访问内存,
	//我们有x个字节,但是第一个字节没有实际含义,需要(int* )
	//这样来强制转换,让编译器明白,我们第一个字节的地址是int类型地址
	//那么当你下次操作时候,编译器就会明白pArr+1 的意思是想下走四个字节的地址
	
	//动态数组和静态数组在使用上方法相同
	*pArr = 4;    //就类似于 a[0] = 4;
	pArr[1] = 10; //就类似于 a[1] = 10;
	printf("%d,%d\n",*pArr,pArr[1]);
	
	free(pArr); //把pArr所代表的动态分配的x字节的内存释放,把控制权限归还给操作系统
	
	return 0; 
}

2 被调函数:调用时为其分配所需内存,调用后直接释放。

#include<stdio.h>
#include<malloc.h>
struct Student
{
    
    
	int sid;
	int age;
};
struct Student CreateStudent(void)
{
    
    
	struct Student st1 = {
    
    88,88}; 
	return st1;
}
void ShowStudents(struct Student st)
{
    
    
	printf("%d %d\n",st.sid,st.age);
}
int main (void)
{
    
    
	struct Student s;
	
	s = CreateStudent();
	ShowStudents(s); //虽然得到结果 88 88 但是你在CreateStudent()使用过、
	                 //的内存已然消失的无影无踪
	
	return 0;
}——》88 88 

3 如何跨函数使用内存呢

用malloc 然后你不去释放


#include<stdio.h>
#include<malloc.h>
struct Student
{
    
    
	int sid;
	int age;
};
struct Student* CreateStudent(void)
{
    
    
	struct Student* p = (struct Student*)malloc(sizeof(struct Student));
	p->sid = 88;
	p->age = 88;
	return p;
}
void ShowStudents(struct Student* pst)
{
    
    
	printf("%d %d\n",pst->sid,pst->age);
}
int main (void)
{
    
    
	struct Student* ps;
	
	ps = CreateStudent();//这样ps就像接盘侠一样把p这块内存给接手了
	ShowStudents(ps);
	               
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/helloworld573/article/details/106034861