**[C语言]**学习笔记一:指针
“&”:取地址操作符
printf中的“*”:取值操作符
一、指针和指针变量:
通常我们所说的指针,就是地址的意思。C 语言中有专门的指针变量用于存放指针,跟普通变量不同,指针变量存储的是一个地址。
指针相当于门牌,指针变量相当于门牌号。
指针变量也有类型,它的类型就是存放的地址指向的数据类型。
EXAMPLE1
#include <stdio.h>
int main()
{
char a = 'f';
int f = 123;
char *pa = &a;//&为取地址符,把a的地址赋给*pa
int *pb = &f;
printf("a = %c\n",*pa);//取pa指针变量中的存储的a地址对应的值’f';通过*解引用,即*pa和变量a代表同一个值
printf("f = %d\n",*pb);
*pa = 'C';
*pa += 1;
printf("now, a = %c\n", *pa);//*为取值操作符
printf("now, f = %d\n", *pb);
printf("sizeof pa = %d\n", sizeof(pa));//读取pa的长度,64位计算机中一个指针存放8位地址
printf("sizeof pb = %d\n", sizeof(pb));
return 0;
}
## RESULT
a = f
f = 123
now, a = D
now, f = 123
sizeof pa = 8
sizeof pb = 8
!!
1、指针变量只能存放地址吗?
答:是的
2、取址运算符(&)作用于一个常数,然后试图打印该常数在内存中的地址,这样做可取吗?
include <stdio.h>
int main()
{
printf("%p\n", &110);
return 0;
}
答:这样做不可取!事实上这涉及到左值和右值的问题
把程序编译一下,报错信息已经提示你了:test.c:5: error: lvalue required as unary ‘&’ operand(c]
意思是:取址操作符(&)的作用对象应该是一个左值,而常数是右值。
LVALUE & RVALUE
lvalue : locator value(特定位置的值),用于识别或定位一个存储位置的标识符。(注意:左值同时还必须是可改变的)。
rvalue : value of an expression(表达式的值),还可以理解为 readable value,即任何可读取的值都被认为是右值(非左值)。
#include <stdio.h>
int main()
{
int a = 5;
++(a++);
return 0;
}
(a++) 是先将变量 a 的值(5)做为整个表达式的值返回,再将 a 自增 1(类似于 a = a + 1)。
所以这里 ++(a++); 相当于 ++(5), a = a + 1;
那当然要报错啦,5 是一个常量,当然不能给你 5 = 5 + 1 咯~
EXAMPLE2
#include <stdio.h>
int main(void)
{
int a, b, c, t;
int *pa, *pb, *pc;
printf("请输入三个数:");
scanf("%d%d%d", &a, &b, &c);
pa = &a;//把a的地址放入pa中
pb = &b;
pc = &c;
if (a > b)
{
t = *pa;//把指针变量pa指向的地址给t;
*pa = *pb;
*pb = t;
}
if (a > c)
{
t = *pa;
*pa = *pc;
*pc = t;
}
if (b > c)
{
t = *pb;
*pb = *pc;
*pc = t;
}
printf("%d <= %d <= %d\n", *pa, *pb, *pc);//把存放在指针变量pa中的地址进行取值并输出;
printf("%d <= %d <= %d\n", a, b, c);
return 0;
}
这个其实很简单
就是1,2,3三个位置和a,b,c三个数比较,先ab比,大的放位置2,小的放位置1;ac比,大的放位置3,小的放位置1,最后bc比。
二、指针和数组
1、*p是取值,*p=&a表示将该地址表示的数值赋予p,即a=p,&a访问的是a的地址,也就是p
2、数组名就是数组第一个元素的地址,也是数组的首地址。
3、指向数组的指针
int a[] = {1, 2, 3, 4, 5};
int *p = a; // 语句1
int *p = &a[0]; // 语句2
因为数组名即数组第一个元素的地址,所以语句 1 和语句 2 是等价的,都是将数组 a 的首地址存放到指针变量 p 中。
4、指针的运算
当指针指向数组元素的时候,我们可以对指针变量进行加减运算,这样做的意义相当于指向距离指针所在位置向前或向后第 n 个元素。
比如 p+1 表示指向 p 指针指向的元素的下一个元素;p-1 则表示指向上一个元素。
需要郑重强调的是:p+1 并不是简单地将地址加 1(int是地址+4等等…),而是指向数组的下一个元素。
char a[] = "FishC";
char *p = a;
printf("*p = %c, *(p+1) = %c“,*p,*(p+1))
*p = F, *(p+1) = i
访问数组元素的方法:
①下标法访问
②指针法访问(先不定义指针也可以访问)
*p = a
*(p+i)=a[i]
PS:
获取字符串长度用xx=strlen();
0、str[3] 用指针法如何表示?
*(str + 3)
1、假设整型指针变量 p 存放的地址值是 0x11008888,那么请问 p + 1,p + 2,p + 4 和 p + 8 的地址分别是?
ans:
p + 1 == 0x11008888 + 4 == 0x1100888C
p + 2 == 0x11008888 + 8 == 0x11008890
p + 4 == 0x11008888 + 16 == 0x11008898
p + 8 == 0x11008888 + 32 == 0x110088A8
2、
……
while (n-- && (*target2++ = *target1++) != '\0')
;
……
3、请问 str[20] 是否可以写成 20[str]?
答:可以。
因为在访问数组的元素的时候,数组名被解释为数组第一个元素的地址。
所以 str[20] == *(str + 20) == *(20 + str) == [20]str
4、使用 fgets 函数(使用文档 -> 传送门)读取用户输入的字符串(英文),并用指针法来计算字符串的字符个数。
#include<stdio.h>
#define MAX 1024
int main()
{
char str[MAX];
char *target = str;//指针法访问数组元素
int length = 0;
printf("请输入一个字符串:");
fgets(str,MAX,stdin);
while (*target++ != '\0')//指针指向数组名,即数组第一个元素,然后每次循环都指向下一位
{
length++;
}
printf("您总共输入了%d个字符",length-1);
return 0;
}
指针数组和数组指针
1、区别:数组名只是一个地址,而指针是一个左值
lvalue : locator value(特定位置的值),用于识别或定位一个存储位置的标识符。(注意:左值同时还必须是可改变的)。
而数组名只是一个地址常量,它不可以被修改,所以数组名不是左值。
所以不能把数组名作为循环判断条件。
2、指针数组
int *p1[5];
指针数组是一个数组,每个数组元素存放一个指针变量。
!! 重点
#include <stdio.h>
int main()
{
char *p1[5] = {
"让编程改变世界 -- 鱼C工作室",
"Just do it -- NIKE",
"一切皆有可能 -- 李宁",
"永不止步 -- 安踏",
"One more thing... -- 苹果"
};
int i;
for (i = 0; i < 5; i++)
{
printf("%s\n", p1[i]);\\不加*是因为要打印的是一个数组元素,加*取值运算符是取数组元素中地址所存放的值(字符)。
}
return 0;
}
3、指针数组
int (*p1)[5];
指针数组是一个指针,它指向的是一个数组。
#include <stdio.h>
int main()
{
int temp[5] = {1, 2, 3, 4, 5};
int (*p2)[5] = &temp;**//必须加&,表示指向整个数组的指针,即取整个数组的地址。不加&的话表示只取数组的第一个元素的地址**
int i;
for (i = 0; i < 5; i++)
{
printf("%d\n", *(*p2 + i));//数组本身是一个指针,指向的是数组的第一个元素。因此指向数组的指针需要取两次值才能得到数组的第一个元素值。
}
return 0;
}
[fishc@localhost s1e23]$ gcc test4.c && ./a.out
1
2
3
4
5