郝斌 ; C语言 ; 指针 ; 笔记
指针 -> 地址 -> 内存单元的编号 -> 8个 bit(0/1) 一个byte(内存单元) // 32位计算机, 32条线(0,1), 2^32 B = [0, 4G-1] // 寻址到字节
注 :
1. 指针就是地址, 地址就是指针
2. 地址就是内存单元的编号 ~ 从零开始的非负整数 // 指针的本质就是操作受限的非负整数, 只能用于减法
3. 指针变量是存放地址的变量
4. 指针 与 指针变量 是两个不同的概念 // 叙述时会把指针变量 简称为 指针
# include
int main(void)
{
int *p; //p是变量名, int *表示 : p变量 存放的是 int类型变量的地址
/*
不表示定义了一个叫 *p 的变量
*/
int i = 3;
p = &i;
/*
1.p保存了i的地址, 因此, p指向i
2.p不是i, i也不是p, 修改p的值不影响i的值, 修改i的值也不影响P的值
3.如果一个指针变量指向了某个普通变量, 则 *指针变量 完全等同于 普通变量
// 所有出现 *p 的地方都可以替换成 i
i *p
*/
//p = i; //error, 类型不一致
//p = 55; //同上
return 0;
}
// *p : 以p的内容为地址的变量
# include
int main(void)
{
int *p; // 其中为垃圾值
int i = 5;
*p = i; // 修改了程序外空间的数据
printf("%d\n", *p);
return 0;
}
# include
int main(void)
{
int i =5;
int *p;
int *q;
p = &i;
//*q = p; // 整形与地址不匹配
//*p = *q; // q未赋值
// p = q; // q把垃圾值赋给p
printf("%d\n", *q);
return 0;
}
*q 不能读取的原因 :
q内部为垃圾值, 没有权限读取(r)读取该内存单元, 直接出错
# include
int main(void)
{
int a = 100;
char str[20] = "A";
printf("%#x, %#x\n", &a, str); // 十六进制输出
return 0;
}
//0x19ff30, 0x19ff1c
通过被调函数修改主调函数相关变量的值 :
1. 实参必须为该变量的值
2. 形参必须为指针变量
3. *形参名 = ... 方式修改主调函数相关变量值
# include
void swap(int * , int *); // 函数声明可不写形参
int main(void)
{
int a = 3;
int b = 5;
swap(&a, &b);
printf("a = %d, b = %d\n", a, b);
return 0;
}
void swap(int *p, int *q)
{
int t;
t = *p;
*p = *q;
*q = t;
return ;
}
1. 地址一般以十六进制保存
2. 一维数组名是个指针变量, 存放的是一维数组第一个元素地址
3.
1. C语言中,没有string类型,用一个字符数组来存放一个字符串
char c[30]={'c', ' ', 'p', 'r', 'o', 'g', 'r', 'a','m'};
3. C语言规定,可以将字符串直接赋值给字符数组
char str[30] = {"C.YuYan"}; //定义时才能将整个字符串一次性地赋值
char str[ ] = "C.YuYan"; //这种形式更加简洁,实际开发中常用
1. '\0' : 字符串结束符;
2. '\0'是 ASCII 码表中的第 0 个字符,英文称为 NUL,中文称为“空字符”。该字符既不能显示,也没有控制功能,输出该字符不会有任何效果,它在C语言中唯一的作用就是作为字符串结束标志.
3. 由" "包围的字符串会自动在末尾添加'\0'. // 注意给'\0'留个位置
4. 字符串长度大于数组长度时,有些较老或者不严格的编译器并不会报错. // 要注意
# include
int main(void)
{
char str[30] = {0}; //将所有元素都初始化为 0,或者说 '\0'
char c;
int i;
for(c = 65, i = 0; c <= 90; c++, i++)
{
str[i] = c;
}
printf("%s\n", str);
printf("%c", str[29]); // 为'\0', 非'0'
return 0;
}
# include
long len = strlen(str); // 不包括'\0'
# include
strcat(arrayName1, arrayName2);
strcat() 将把 arrayName2 连接到 arrayName1 后面,并删除原来 arrayName1 最后的结束标志'\0'。
这意味着,arrayName1 必须足够长,要能够同时容纳 arrayName1 和 arrayName2,否则会越界(超出范围)。
strcat() 的返回值为 arrayName1 的地址。
strcpy() 会把 arrayName2 中的字符串拷贝到 arrayName1 中,字符串结束标志'\0'也一同拷贝。
字符本身没有大小之分,strcmp() 以各个字符对应的 ASCII 码值进行比较。
strcmp() 从两个字符串的第 0 个字符开始比较,如果它们相等,就继续比较下一个字符,
直到遇见不同的字符,或者到字符串的末尾。
返回值:若 arrayName1 和 arrayName2 相同,则返回0;
若 arrayName1 大于 arrayName2,则返回大于 0 的值;
若 arrayName1 小于 arrayName2,则返回小于0 的值。
1. 数组长度必须事先制定, 且只能是常整数, 不能是变量
int a[5]; // ok
int len = 5; int a[len]; //error
2. 数组占用内存程序员无法手动释放, 函数运行完毕时, 数组空间才会被系统释放
3. 数组长度不能更改
4. A函数中定义的数组, 在A函数运行期间可以被其他函数使用; A函数执行完毕后,无法被其他函数使用
为什么需要动态分配内存 :
动态数组很好的解决了传统数组的4个缺陷, 传统数组也叫静态数组
1. 要使用malloc函数, 必须添加 malloc.h 头文件
2. malloc 函数只有 1个形参, 且形参为整型
3. n表示请求系统为本程序分配n个字节
4. malloc函数只能返回第1个字节的地址
5. 最终分配 n+4个字节 // p变量, 静态占4个字节
char * 200个变量
int * 50个变量
double * 25个变量
( )malloc(200);
23/05/23 - 未完结