数据结构学习C语言前导知识
指针:C语言的灵魂
-
内存被释放的意思是说,操作系统回收了对一个变量所分配内存的控制权限,但是保存其中的垃圾数据依旧在保存着,不会清空遗留下的数据。所以任何变量要初始化后才能使用,否则里面可能存放着之前的垃圾数据。
-
内存是多字节组成的线性一维存储空间。内存的基本划分单位是字节。每个字节含有8位。每一位存放1个0或1个1,字节和编号是一一对应的。每个字节都有一个唯一确定的编号,一个编号对应一个字节。这个编号也叫地址。一个系统所能管理的内存空间的大小取决于参与编号的二进制位数,而二进制位数由地址总线位数决定。
-
指针初始化:
int i = 10; int *p = &i;
p指向i,改变p的值不影响i的值,改变i的值不影响p的值;*p与 i完全等价。常量和表达式之前不能加取地址&。
-
如何通过被调函数修改主调函数中普通变量的值:
-
实参为相关变量的地址;
-
形参为以该变量的类型为类型的指针变量;
-
在被调函数中通过 *形参变量名 的方式就可以修改主调函数中变量的值。
#include <stdio.h>
int f(int * p)
{
*p = 100;
}
int main()
{
int i = 9;
f(&i);
printf("%d\n", i);
return 0;
}
指针和一维数组
-
数组名
一维数组名是个指针常量,它存放的是一维数组第一个元素的地址,它的值不能改变,一维数组名指向的是数组的第一个元素。
-
下标和指针的关系:
a[ i ] 等价于* (a+i),a[3]在汇编语言中也可以写成3[a]。
假设指针变量的名字为p,则p + i的值是p + i *(p所指向的变量所占的字节数)
-
指针变量的运算: 指针变量不能相加,不能相乘,不能相除,如果两个指针变量属于同一数组,则可以相减。指针变量可以加减一个整数,前提是最终结果不能超过指针允许指向的范围。
p++ 等价于p+1
-
使用 %p 打印地址,按照16进制形式打印指针地址,32位编译器下会打印16进制的21位地址,64位编译器下会打印16进制的32位地址。
-
如何使用被调函数修改主调函数中一维数组的内容:通过①存在数组首元素的指针变量。②存放数据元素长度的整型变量。
指针的大小
指针变量,无论它指向的变量占几个字节,该指针变量本身只占四个字节。以32位地址空间为例,32根地址总线,每个字节表示8位,因此有4字节。一个变量的地址使用该变量首字节的地址来表示。
至于如何通过指针取对应类型的数字,看这个指针是什么类型,例如如果是(char *),会往后取一个字节,如果是(double * )指向前八个字节。但是指针变量本身只占4个字节。
char数组赋值问题
遇到一个对char数组赋值的问题,对字符数组赋值只有三个方式
-
在定义的时候直接用字符串赋值:
char a[10]="hello";
绝对不能先定义再给它赋值,如下这样是错误的。
char a[10]; a[10]="hello";
-
对数组中字符逐个赋值,字符串可以赋值给字符指针变量,或者将字符串用字符数组保存。
char a[10]={'h','e','l','l','o'};
-
函数把 src 所指向的字符串复制到 dest,例如
char *strcpy(char *dest, const char *src); char src[40]; strcpy(src, "This is runoob.com");
使用这个函数在VS2005以上版本(VS2005、VS2008、VS2010)下编译需要在开头添加
#define _CRT_SECURE_NO_WARNINGS
结构体的使用
结构体变量不能加减乘除,当时可以相互赋值。
普通结构体变量和结构体指针变量作为函数传参的问题,与通过指针被调函数修改主调函数的值的方式相同。(*和&)
使用结构体的两种方式:
struct student
{ int sid;
char name[200];
double age;
};
struct student std;
struct student *pstd = &std;
std.age = 10; //方式①
pstd->age = 30;//方式②,pstd->age等价于(*pstd).age
内存的动态分配和释放用法
-
malloc()只能返回第一个字节的地址,但并不知道此刻指向的第一个字节是什么类型,所以必须添加数据指针类型强制转换。
比如(char * )malloc(200)返回200个变量的指针;
(int * )malloc(200)返回50个变量的指针;
(double* )malloc(200)返回25个变量的指针。
-
int* p = (int * )malloc(4); 这个函数分配了8个字节的空间,其中p变量占4个字节,p所指向的内存也占了4个字节。p本身所占的内存是静态分配的,p所指向的内存是动态分配的。p本身所占的内存是静态的,不能由程序员手动去释放,只能由p变量所在的函数运行终止时由系统释放。然后free(p);
-
释放p指向的动态分配的内存。( * p)同样表示一个int变量,只是这个整形变量的内存分配方式是动态的。
#include <stdio.h> #include <malloc.h> int main() { int len = 0; printf("输入你的数组长度:\n "); scanf_s(" %d", &len, len); int* Arrlist = (int *)malloc(sizeof(int) * len); for (int i = 0; i < len; i++) scanf_s(" %d", &Arrlist[i]); for (int j = 0; j < len; j++) printf("%d ", *(Arrlist + j)); free(Arrlist); return 0; }
scanf_s() 是针对“ scanf()在读取字符串时不检查边界,可能会造成内存泄露”这个问题设计的。scanf_s()用于读取字符串时,必须提供一个数字以表明最多读取多少位字符,以防止溢出。
-
void *realloc(void *ptr, size_t size)
表示尝试重新调整之前调用 malloc 所分配的 ptr 所指向的内存块的大小
ptr -- 指针指向一个要重新分配内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果为空指针,则会分配一个新的内存块,且函数返回一个指向它的指针。
size -- 内存块的新的大小,以字节为单位。如果大小为 0,且 ptr 指向一个已存在的内存块,则 ptr 所指向的内存块会被释放,并返回一个空指针。
char *str; str = (char*)malloc(sizeof(char) * 4); str = (char*)realloc(str, sizeof(char) * 100);
- 传统数组不能跨函数使用,静态内存是由栈分配的,函数的调用通过压栈和出栈实现,静态内存在函数执行结束的时候就会被释放。需要使用malloc()申请动态内存,但是一定记得要释放空间。
typedef关键字
typedef 关键字,您可以使用它来为类型取一个新的名字,如下是一个新的使用方法,更加便于使用。
#include <stdio.h>
typedef struct student
{
int age;
char name[100];
int ID;
}*PST, STU; //PST等价于*struct student,STU相当于struct student
int main()
{
STU students;
PST pst = &students;
pst->age = 33;
printf("age is %d\n", pst->age);
return 0;
}