指针有什么用?
场景A
通过函数交换两个变量的值
eg. 交换变量a,b的值
int swap(int *a, int *b){
int temp = 0;
temp = *a;
*a = *b;
*b = temp;
}
场景B
返回结果有多个,或return返回状态,指针返回结果
int divide(int a,int b,float *res){
int ret = 1;
if(b != 0){
*res = (float)a/b;
}else{
ret = 0;
}
return ret;
}
指针最常见的错误
定义了指针变量,但是没有指向任何变量,就开始使用。
int main(){
int *p;
*p = 12;
printf("%d",*p);
return 0;
}
指针与数组
数组变量是特殊的指针
- 数组变量本身表达地址。所以
- int a[10]; int* p = a; //无需用&取地址
- 但是数组的单元表达的是变量,需要用&取地址
- a == &a[0]
- []运算符可以对数组做,也可以对指针做
- p[0] <==> a[0]
- 运算符可以对指针做,也可以对数组做
- *a 操作的是数组的第一个单元
- 数组变量是const的指针,不能被赋值
- int b[] --> int * const b;
指针与const
如果指针被const修饰
- 表示一旦得到了某个变量的地址就不能再指向其他变量
- int * const q = &i; // 指针 q 是 const
- *q = 26; // OK
- q++; // Error
如果所指是const
- 表示不能通过指针修改那个变量(并不能使那个变量成为const)
- const int *p = &i;
- *p = 26; // Error
- i = 26; // OK
- p = &j; //OK
这些都是啥意思?
int i;
const int* p1 = &i;
int const* p2 = &i;
int *const p3 = &i;
- 判断哪个被const了标志是const在*的前面还是后面
- const * :所指被const了
- * const :指针被const了
转换
- 总是可以把一个非const的值转换成const的
void f(const int * x);
// const int * x; 所指被const了,表示传入的变量在这个函数中绝对不会被修改
int a = 15;
f(&a); // ok,传入一个非const值,转换为const,不能修改
const int b = a;
f(&b); // ok,传入const值,不能修改
f(const int * x){
x++; // error,const不能修改
}
- 当要传递的参数的类型比地址大的时候,这是常用的手段:既能用比较少的字节数传递值给参数,又能避免函数对外面的变量修改
const数组
- const int a[] =
- 数组变量本身就是const指针,这里的const表明数组的每个单元都是const int
- 所以必须通过初始化进行赋值
保护数组值
- 因为把数组传入函数时传入的是地址,所以函数可以修改数组值
- 传入时用const修饰,可以保护数组值不被函数修改
- int f(const int arr[]);
指针运算
指针+1的含义
- 给一个指针加1表示要让这个指针指向下一个单元的变量
int a[10];
int *p = a;
*p -> a[0];
*(p+a) -> a[1];
- 如果指针不是指向一片连续分配的空间(如数组),则这种运算没有意义。
指针可用的运算符
- 给指针加减一个整数 (+ , += , - , -=)
- 递增递减 (++ , --)
- 两个指针相减(返回两个指针之间的距离)
int a[] = {5,4,3,2,1};
int *p1 = &a[1];
int *p2 = &a[4];
printf("%d\n",p2-p1); // 输出结果:3
指针的大小比较
- 两个指针可以比较大小
- 只有在两个指针指向同一数组时比较才有意义
- 比较结果依赖于指针在数组中的相对位置
int a[] = {1,0};
int *p = &a[0];
int *q = &a[1];
printf("%d",p>q); //输出0
printf("%d",*p>*q); //输出1
指向符合字面量的指针
int *p = (int []){0,1,2,3,5};
C99特性,可以减少一些麻烦。不用声明一个数组,再用指针指向这个数组的第一位。
指针用于数据处理
*和++运算符的组合
++ 优先级大于 *
表达式 | 含义 |
---|---|
*p++ 或 *(p++) | 自增前表达式的值是*p,然后自增p |
(*p)** | 自增前表达式的值时*p,然后自增*p |
*++p或者*(++p) | 先自增p,自增后表达式的值仍是*p |
++*p或者++(*p) | 先自增*p,自增后表达式的值仍是*p |
动态内存分配
在C99中,可以用变量做数组定义的大小,C99之前呢?
C99之前可以给指针分配一定大小的内存,来存放数组,这样就能实现定义数组的大小。
int *arr = (int*)malloc(n*sizeof(int));
malloc分配的是void*,需要强制转换成int*,然后用数组大小n乘以单个int占用的字节就可以把能存放n个int型的空间分配给了*arr。
malloc
-
使用malloc函数需要引入头文件
stdlib.h
-
malloc返回一个指针,类型为void*
-
如果malloc请求失败,返回NULL
-
malloc的参数为size,以字节为单位
-
使用free()释放内存
小记
对于以下代码段,正确的说法是:
char *p;
while(1){
p = malloc(1);
*p = 0;
}
- A. 最终程序会因为没有没有空间了而退出
- B. 最终程序会因为向0地址写入而退出
- C. 程序会一直运行下去
- D. 程序不能被编译
正确为B选项。一直给p分配内存,但不释放,最终malloc会因内存不足而请求失败,返回NULL。此时指针p的地址指向了NULL(0地址),此时对0地址写入,系统崩溃退出。
单字符的输入输出
putchar
- int putchar(int c);
- 向标准输出写一个字符
- 返回写了几个字符,EOF(-1)表示写失败
getchar
- int getchar(void);
- 从标准输入读取一个字符
- 返回类型为int,是为了返回EOF(-1)
- Windows -> Ctrl+Z
- Unix -> Ctrl+D
字符串数组
- char **a
- a是一个指针,指向另一个指针,那个指针指向一个字符(串)
- char a[][n]
- 一个数组a,每个单元都能放下长度为10的字符(串)
- 缺点,字符串长度固定,不能超出
- char *a[]
- 一个数组a,每个单元都是一个char*,可以存放字符串
- 相比a[][],字符串的长度不受限制
程序参数
- int main(int argc,char const *argv[])
- argc是argv字符串数组的数量
- argv[0] 是启动程序的命令本身
- 当使用符号链接时,反应符号链接的名字
- 当然可以不叫argc和argv,名字可以自己取
#include<stdio.h>
int main(int n,char const *a[]){
for(int i = 0; i < n; i++){
printf("%d => %s\n",i,a[i]);
}
return 0;
}
将该文件编译为叫做test的程序,使用 ./test
运行
0 => ./test
使用 ./test abc def 114 514
运行
0 => ./test
1 => abc
2 => def
3 => 114
4 => 514
使用 ln -s test test2
创建符号链接
使用 ./test2 abc def 114 514
运行
0 => ./test2
1 => abc
2 => def
3 => 114
4 => 514
标签:const,变量,int,笔记,C语言,++,数组,指针
From: https://www.cnblogs.com/orzmiku/p/17644186.html