9 指针与字符串2
1 指针使用
- 指针的应用:1、函数返回多个值,某些值只能通过指针返回。传入的参数实际上是需要保存带回的结果的变量;2、函数返回运算的状态,结果通过指针返回,常用的套路是让函数返回特殊的不属于有效范围内的值表示出错,例如0、-1等。但是任何数值都是有效时,必须分开返回。
- 交换两个变量:
void swap(int *pa, int *pb){
int t = *pa;
*pa = *pb;
*pb = t
}
- 传入函数的数组int a[]成了什么?函数参数中的数组其实是int*,sizeof返回4,它变成了指针。如果改成int *a 依然可以编译运行成功。
- 函数参数表中的数组是指针。sizeof(a) = sizeof(int *)。但是可以用数组的运算符[]进行运算。
- 下面四种函数原型等价:
- int sum(int *ar, int n);
- int sum(int *, int);
- int sum(int ar[], int n);
- int sum(int [], int);
数组变量是特殊的指针。
- 数组变量本身表达地址,所以:
- int a[10]; int *p = a; 无需用&取地址
- 但是数组的单元表达的是变量,需用&取地址
- a == &a[0]
- []运算符可以对数组做,也可以对指针做:
- p[0] 等价于 a[0]
- *运算符可以对指针做,也可以对数组做:
- *a = 25;
- 数组变量是const的指针,所以不能被赋值
- 数组变量本身表达地址,所以:
指针是const:
- 表示一旦得到了某个变量的地址,不能再指向其他变量
- 所指是const:
- 表示不能通过指针去修改这个变量,但是这个变量依然可以变
int i;
const int* p1 = &i; //变量不能通过指针修改
int const* p2 = &i; //变量不能通过指针修改
int *const p3 = &i; //指针不能被修改
- 当要传递的参数的类型比地址大的时候,这是常用的手段:既能用比较少的字节数传递值给参数,又能避免函数对外面的变量的修改。
- const int a[] = {1,2,3};
- 数组变量已经是const的指针了,这里的const表示数组的每个单元都是const int,所以必须通过初始化进行赋值。
- 因为把数组传入函数时传递的是地址,所以函数内部可以修改数组的值。为了保护数组不被函数破坏,可以设置参数为const
2 指针运算
- char,指针加1地址加1;int,指针加1地址加4
- 给指针加1表示让指针指向下一个变量,如果指针不是指向一片连续分配的空间,如数组,则这种运算没有意义。
- *p++:取出p所指的数据,再把p移到下一个位置,常用于数组类的连续空间操作。
0地址:
- 内存中有0地址,但是0地址通常是个不能随便碰的地址,所以指针不应该具有0值
- 用0值做特殊的事情:
- 返回的指针无效
- 指针没有被真正初始化(先初始化为0)
- NULL是个预先定义的符号,表示0地址
- 有的编译器不愿意你用0表示0地址
void*表示不知道指向什么东西的指针,计算时与char*相同
- 指针也可以转换类型:int*p = &i; void *q = (void*)P;
用指针做什么?
- 需要传入较大的数据时用做参数
- 传入数组后对数组操作
- 函数返回不止一个结果
- 动态申请内存
C99可以用变量做数组定义的大小
- malloc大小以字节为单位,返回类型为void*,free只能还申请来的空间的首地址
include<stdlib.h>
int *a = (int*)malloc(n*sizeof(int));
free(a);
3 字符串操作
- int putchar(int c);
- 向标准输出写一个字符
- 返回写了几个字符,EOF(-1)表示失败,end of file
- int getchar(void);
- 从标准输入读入一个字符,返回类型是int为了返回EOF(-1)
- windows-ctrl+Z,unix-ctrl+D
键盘和屏幕中间有一个shell,用户输入是给shell填缓冲区,getchar和scanf只是在缓冲区读东西。
char **a;
- a是一个指针,指向另一个指针,那个指针指向一个字符(串)
- char a[][10];
- a是二维数组,第二维需要确定的数值
char *a[];
程序参数:
int main(int argc, char const *argv[])
argv[0]是命令本身
4 字符串函数
- strlen:返回字符串长度
size_t strlen(const char *s);
int mylen(const char *s){
int idx = 0;
while(s[idx] != '\0'){
idx++;
}
return idx;
}
- strcmp:比较字符串,返回0(s1==s2),1(s1>s2),-1(s1
int strcmp(const char* s1, const char *s2);
int mycmp(const char* s1, const char* s2){
int idx = 0;
while(s1[idx] == s2[idx] && s1[idx] != '\0'){
idx++;
}
return s1[idx] - s2[idx];
}
int mycmp(const char* s1, const char* s2){
while(*s1 == *s2 && *s1 != '\0'){
s1++;
s2++;
}
return *s1 - *s2;
}
- strcpy:把src的字符拷贝到dst,restrict表明src和dst不重叠,返回dst
char *strcpy(char *restrict dst, const char *restrict src);
char* mycpy(char *dst, const char* src){
char *ret = dst;
while(*dst++ = *src++);
*dst = '\0';
return ret;
}
char* mycpy(char *dst, const char* src){
int idx = 0;
while(src[idx] != '\0'){
dst[idx] = src[idx];
idx++;
}
dst[idx] = '\0';
return dst;
}
复制一个字符串:
char *dst = (char*)malloc(strlen(src) + 1);
strcpy(dst, src);
- strchr:字符串中找字符
- char *strchr(const char *s, int c);
- 字符串中找字符串:char *strstr(const char *s1, const char *s2)
- 忽略大小写:char *strcasestr(const char *s1, const char *s2)