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