C 语言答疑-04
By Von Brank | 2020/11/23
目录
- 网站推荐
- 近期知识梳理
- 几道题
- 答疑
网站推荐
- 算法可视化:visualgo.net/zh
- 算法学习:oi-wiki.org
知识点梳理
指针
&
:取地址的运算
scanf("%d", &n);
里的&
是什么%p
用来输出地址int i = 0; printf("0x%x\n", &i);
int i = 0; int p; int p = (int)&i; printf("0x%x\n", p); printf("%p\n", &i);
32 位与 64 位的区别
int i = 0; printf("%lu\n", sizeof(int)); printf("%lu\n", sizeof(&i));
&
可以用于获得变量的地址,它的操作数必须是变量不能对没有地址的东西取地址
以下写法是正确的
int i = 0; printf("%p\n", &i);
以下写法都是错误的
int a = 0, b = 1; printf("%p\n", &(a++)); printf("%p\n", &(++a)); printf("%p\n", &(a + b));
&
些别的
相邻变量的地址
int a = 0, b = 1; printf("%p\n%p\n", &a, &b);
C 语言的变量存储在“栈”中
sizeof
一个&
的结果int i = 0; printf("%d\n", sizeof(&a));
数组的地址,首个数组单元的地址,相邻元素的地址
int a[100]; printf("%p\n", a); printf("%p\n", &a[0]); printf("%p\n", &a[1]); printf("%p\n", &a[2]);
指针变量
scanf("%d", &n)
是什么scanf
函数需要传入一个变量的地址,便于赋值scanf
函数需要对控制串进行处理scanf
函数的内部实现也仅仅是基于 C 语言的基本语法
指针变量的定义
以下代码将
i
的地址赋给p
int i; int *p = &i;
以下两种写法意思相同
int *p; int* p;
以下写法定义了一个指针变量
p
和一个int
类型的变量q
int *p, q;
以下写法定义了两个指针变量
p
和q
int *p, *q;
访问地址上的变量*
int i = 10; int *p = &i; printf("%d\n", i); printf("%d\n", *p); *p = 20; printf("%d\n", i); printf("%d\n", *p);
指针作为函数参数传入
比较函数
f
和g
的输出差异#include <stdio> void f(int *p) { printf("%d\n", *p); printf("%p\n", p); } void g(int k) { printf("%d\n", k); printf("%p\n", &k); } int main() { int i = 10; f(&i); g(i); return 0; }
&
与*
互为反作用int i = 10; int *p = &i; printf("%d\n", i); printf("%d\n", *&i); printf("%p\n", p); printf("%p\n", &*p);
scanf("%d", i);
出错的原因
指针与数组
以下两段代码效果相同
#include <stdio.h> void f(int a[], int start, int end) { for(int i=start; i<=end; i++) { printf("%d ", a[i]); } } int main() { int start, end; int a[100] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29}; start = 1; end = 10; f(a, start, end); return 0; }
#include <stdio.h> void f(int *a, int start, int end) { for(int i=start; i<=end; i++) { printf("%d ", a[i]); } } int main() { int start, end; int a[100] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29}; start = 1; end = 10; f(a, start, end); return 0; }
以下函数原型等价
int sum(int *p, int i); int sum(int *, int i); int sum(int a[], int i); int sum(int [], int i);
数组变量本身就是特殊的指针
以下操作无需取地址符
int a[100]; int *p = a;
数组的单元表达的是变量,需要取地址,如:
if(a == &a[0]) { printf("YES!!!"); }
[]
运算符也可以用于指针,如int a = 10; int *p = &a; printf("%d\n", *p); printf("%d\n", p[0]);
*
也可以用于数组int a[100] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29}; a[0] = 123; printf("%d\n", a[0]); printf("%d\n", *a); *a = 456; printf("%d\n", a[0]); printf("%d\n", *a);
数组变量是常量(const),即
int a[]
等价于int * const a
,因此:以下写法是错误的
int a = {0, 1, 2, 3}; int b[] = a;
以下写法是正确的
int a = {0, 1, 2, 3}; int *p = a;
const 指针
int * const p = &i;
的含义表示指针变量
p
只能指向i
的地址int i, j; int * const p = &i; *p = 123; //可以 p = &j; //不可以
const int *p = &i
的含义表示不允许通过
*p
来修改变量的值int i, j; const int *p = &i; *p = 123; //不可以 i = 456; //可以 p = &j; //可以
分辨以下写法的区别
const int* p = &i;
表示不能通过*p
来修改变量的值int const* p = &i;
表示不能通过*p
来修改变量的值int *const p = &i;
表示不能改变指针变量p
指向的变量
可以用于防止函数修改指针所指向变量的值或数组的值,保证安全性
#include <stdio.h> void f(const int* a) { int b = *a; //可以 *a = 123; //不可以 }
常量数组
const
类型的数组只能使用集成初始化const int a[] = {0, 1, 2, 3, 4, 5};
指针的运算
对于一个指针变量
p
,p + 1
的含义不是让指针的值+1
,而是加上sizeof(<指针变量指向的变量类型>)
char s[] = "hello_world"; char *p = s; printf("%p\n", p); printf("%p\n", p + 1); int a[] = {0, 1, 2, 3, 4, 5, 6}; int *q = a; printf("%p\n", q); printf("%p\n", q + 1);
char s[] = "hello_world"; char *p = s; printf("%c\n", *p); printf("%c\n", *(p + 1)); int a[] = {0, 1, 2, 3, 4, 5, 6}; int *q = a; printf("%d\n", *q); printf("%d\n", *(q + 1));
int a[105]; for(int i=1; i<=100; i++) { scanf("%d", a + i); } for(int i=1; i<=100; i++) { printf("%d", a + i); }
a[i]
和*(a + i)
完全等价指针变量可以进行加减,但指针的乘除没有意义
int a[100]; int *p1 = a; int *p2 = &a[7]; printf("p1 = %p\n", p1); printf("p2 = %p\n", p2); printf("p2 - p1 = %d\n", p2 - p1);
*p++
表示取出p
指向的那个数据,然后将p
移动到下一个位置int a[] = {0, 1, 2, 3, 4, 5, 6, 7, -1}; int *p = a; while(*p != -1) { printf("%d ", *p++); }
指针使用的其他注意事项
所有指针的大小都是一样的,32 位程序的指针是 4 字节,64 位是 8 字节
为了防止使用出错,指向不同数据类型的指针不能相互赋值,如:
int *p = &n; char *q = &c; p = q;
void*
表示指向未知类型的指针,编译器不知道它指向的是什么数据类型int *p1 = &n; char *p2 = &c; void *p3; p3 = p1; p3 = p2;
指针也可以做强制类型转换
int *p = &n; char *q = &c; p = (void*)q;
指针究竟有什么用
- 便于向函数中传入大量数据,如数组作为参数传入
- 将数组传入函数后对数组作操作
- 函数需要返回一个数组
- 用函数修改外部变量的值
- 动态内存分配
几道题
关于指针的题没几道,关于链表的倒是有不少(bushi