[C语言]进阶|指针与字符串

------------------------------------------------------------------------------------

回顾:[C语言]指针与字符串

指针的使用:

/**
* main.c by weiChen in 2015-5-4
*/
#include <stdio.h> //定义函数体,使在main方法中能调用
void swap(int *pa, int *pb);
void minmax(int c[], int len, int *min, int *max);
int divide(int d, int e, int *result); int main(void)
{
/*
指针应用场景:
1. 交换两个变量的值 2. 函数返回多个值,某些值就只能通过指针返回;
传入的参数实际上是需要保存带回的结果的变量(注:函数中指针的值将作为参数传入函数); 3. 函数返回运算的状态,结果通过指针返回;
常用的套路是让函数返回特殊的不属于有效范围内的值来表示出错;
-1或0(在文件操作会看到大量的例子)
但是当任何数值都是有效的可能结果时,就得分开返回了;
后续的语言(c++,java)采用了异常机制来解决这个问题
4. 指针常见错误:定义了指针变量,还没有指向任何变量,就开始使用指针
*/
int a = ;
int b = ;
swap(&a, &b);
printf("a=%d,b=%d\n", a, b); int c[] = {,,,,,,,,,};
int min,max;
minmax(c, sizeof(c)/sizeof(c[]), &min, &max);
printf("min=%d, max=%d\n", min, max); int d = ;
int e = ;
int f;
if(divide(d, e, &f)) {
printf("%d/%d=%d\n", d, e, f);
} int i = ;
int *p;
int k;
k = ;
*p = ;//未初始化变量,直接给指针赋值;一旦指针所指的位置不可写,程序将报错
printf("&i=%p\n", &i);//Segmentation fault return ;
} //交换两个值
void swap(int *pa, int *pb)
{
int t = *pa;
*pa = *pb;
*pb = t;
} //求最小最大值
//虽然*min,*max是作为参数传进去的,但作用是得到结果,带入
void minmax(int a[], int len, int *min, int *max)
{
int i;
*min = *max = a[];
for(i=; i<len; i++) {
if(a[i] < *min) {
*min = a[i];
}
if(a[i] > *max) {
*max = a[i];
}
}
} //@return 如果除法成功,返回1;否则返回0
int divide(int d, int e, int *result)
{
int ret = ;
if(e == ) {
ret = ;
} else {
*result = d/e;
}
return ret;
}
/**
* main.c by weiChen in 2015-5-4
*/
#include <stdio.sh> int main(void)
{
/*
指针与const
指针可以是const: 0xaffefado
值可以是const: 45
*/ /*
指针是const: 表示一旦得到了某个变量的地址,不能再指向其他变量
int *const q = &i; //q的值是const,值是i的指针
*q = 26; //OK
q++; //ERROR
*/ /*
所指是const:表示不能通过这个指针去修改那个变量(并不能使得那个变量成为const)
const int *p = &i;
*p = 26; //ERROR, (*p是const)
i = 26; //OK
p = &j; //OK
*/ /*
int i; const int *p1 = &i; \
| 指针不能被修改
int const *p2 = &i; / int *const p3 = &i; //判断哪个被const了的标志是const在*的前面还是后面
*/ /*
转换:总是可以把一个非const的值转换成const的
void f(const int *x); //意思:传入一个const指针参数,但函数内部不会更改这个指针所指的值
int a = 15; //可以传入一个非const的指针的值
f(&a); //OK const int b = a; //也可以传入一个非const的指针的值
f(&b); //OK
b = a + 1; //ERROR //当要传递的参数的类型比地址大的时候,这是常用的手段:既能用比较少的字节数传递值给参数,又能避免函数对外面的变量的修改
*/ /*
const数组:
const int a[] = {1,2,3,4,5,6,};
数组变量已经是const的指针了,这里的const表明数组的每个单元都是const int (即a[0]等均为const)
所以必须通过初始化进行赋值
*/ /*
保护数组值:
因为把数组传入函数时传递的是地址,所以那个函数内部可以修改数组的值
为了保护数组不被函数破坏,可以设置参数为const
int sum(const int a[], int length); //不希望函数对参数作修改
*/ return ;
}

指针的计算:

/**
* main.c
*/
#include <stdio.h> int main(void)
{
char ac[] = {,,,,,,,}; //char数组
char *p = ac; //*p指向数组的第一个单元
printf("p = %p\n", p); //p = 0x7fff51f1dc15
printf("p + 1 = %p\n", p + ); //p + 1 = 0x7fff51f1dc16 int ai[] = {,,,,,,,}; //int数组
int *q = ai; //*p指向数组的第一个单元
printf("q = %p\n", q); //q = 0x7fff50160bf0
printf("q + 1 = %p\n", q + ); //q + 1 = 0x7fff50160bf4 printf("sizeof(char)=%ld\n", sizeof(char)); //
printf("sizeof(int)=%ld\n", sizeof(int)); // /*
指针的计算:
在指针上加1,是移到下一个单元,给实际的指针值加上sizeof类型的值
两个指针相减,值是两个指针的差除以sizeof类型的值
*/ // *p -> ac[0]
// *(p+1) -> ac[1]
// *(p+n) -> ac[n]
// 加1如果不加上sizeof(类型)的值,得到的其实并不是我们想要的 // 给指针加1表示要让指针指向下一个变量:
// int a[10];
// int *p = a;
// *(p+1) -> a[1];
// 如果指针不是指向一片连续分配的空间,如数组,则这种运算没有意义 /*
指针计算:
给指针加减一个整数(+, +=, -, -=)
递增递减(++/--)
两个指针相减:值是有几个sizeof类型的值存在
*/
while(*p!=-) {
printf("%d\n", *p++);
}
/* *p++
取出p所指的那个数据,顺便把p移到下一个位置去
*的优先级虽然高,但是没有++高
常用于数组类的连续空间操作
在某些cpu指令上,这可以直接被翻译成一条汇编指令
*/ /*
指针比较:
<, <=, ==, >, >=, != 都可以对指针做
比较他们在内存中的地址
数组中的单元的地址肯定是线性递增的
*/ /*
0地址:
当然你的内存中有0地址,但是0地址通常是个不能随便碰的地址
所以你的指针不应该具有0值
因此可以用0地址来表示特殊的事情
返回的指针是无效的
指针没有被真正初始化(先初始化为0)
NULL是一个预定义的符号,表示0地址,有些编译器不识别小些的null
有的编译器不愿意你用0来表示0地址
*/ /*
指针的类型:
无论指向什么类型,所有的指针的大小都是一样的,因为都是地址
但是指向不同类型的指针是不能直接互相赋值的
这是为了避免用错指针
*/ /*
指针的类型转换:
void* 表示不知道指向什么东西的指针
计算时与char* 相同(但不相通)
指针也可以转换类型
int *p = &i; void *q = (void*)p;//通过p看i是一个int,通过q看i是一个void(强制类型转换后赋给q)
这并没有改变p所指的变量的类型,而是让后人用不同的眼光通过p看它所指的变量
不再当你是int,而认为是void
*/ /*
用指针来做什么:
需要传入较大的数据时用作参数
传入数组后对数组做操作
函数返回不止一个结果
需要用函数来修改不止一个变量
动态申请的内存
*/
return ;
}

动态内存分配:

//  main.c
// Created by weichen on 15/6/10.
// Copyright (c) 2015年 weichen. All rights reserved.
#include <stdio.h>
#include <stdlib.h> int main(int argc, const char * argv[]) {
/*
动态内存分配 输入数据:输入数据时,先告诉你个数,然后再输入,要记录每个数据
C99可以用变量做数组定义的大小,C99之前呢?int *a = (int*)malloc(n*sizeof(int)); #include <stdlib.h>
void* malloc(size_t size);
1. 向malloc申请的空间的大小是以字节为单位的
2. 返回的结果是void*,需要类型转换为自己需要的类型
3. (int*)malloc(n*sizeof(int));
*/ int number;
int* a;
int i; printf("输入数量:");
scanf("%d", &number);
// int a[number]; // C99写法
a = (int*)malloc(number*sizeof(int)); //malloc返回的void*,所以需要类型转换一下,现在a就可以当做数组使用 for (i=; i<number; i++) {
scanf("%d", &a[i]);
}
for (i=number; i>=; i--) {
printf("%d", a[i]);
} free(a); // 归还内存 return ;
}
/**
* main.c
*/
#include <stdio.h>
#include <stdlib.h> int main(int argc, const char * argv[]) {
// malloc:如果空间申请失败则返回0或者NULL void *p = ; //free可以释放0或NULL,避免free的地址没有被分配时出错,习惯初始化指针为0
int cnt = ;
// 如果p的地址不是0(得到了地址),循环继续
while( (p = malloc(**)) ) {
cnt++;
}
printf("分配了%d00MB的空间\n", cnt); free(p); /*
p = malloc(100*1024*1024);
p++; // pointer being freed was not allocated
p = &i; // pointer being freed was not allocated
free(p);
*/ /*
把申请得到的空间还给“系统”
申请过的空间,最终都应该要还
只能还申请来的空间的首地址 常见问题:
申请了没有free,长时间运行内存逐渐下降:忘了或找不到合适的free的时机
free过了再free
地址变过了,直接取free
*/ return ;
}

字符串操作:

/**
* main.c
*/ #include <stdio.h> int main(int argc, const char * argv[]) {
/*
单字符输入输出: putchar,getchar int putchar(int c);
向标准输出写一个字符
返回写了几个字符,EOF (-1)表示写失败(end of file) int getchar(void);
从标准输入读入一个字符
返回类型是int是为了返回EOF (-1):Windows->Ctrl-Z
Unix->Ctrl-D
*/ int ch; while( (ch = getchar()) != EOF ) {
putchar(ch);
} return ; /*
字符串数组:
char **a;
a是一个指针,指向另一个指针,那个指针指向一个字符(串)
char a[][1]; */
}

字符串函数实现:

//  main.c
// Created by weichen on 15/6/23.
// Copyright (c) 2015年 weichen. All rights reserved. #include <stdio.h>
#include <string.h>
//自定义求长度的函数
int mylen(const char *s) {
int index = ;
//知道长度用for循环, 不知道用while
while (s[index] != '\0') {
index++;
}
return index;
} int main(int argc, const char * argv[]) {

   /**
   * size_t strlen(const char *s);
* 返回s的字符串长度(不包括结尾的0)
   */
char line[] = "hello";

   printf("strlen=%d\n", strlen(line)); //strlen=5 printf("strlen=%d\n", mylen(line)); printf("sizeof=%d", sizeof(line)); //sizeof=6 return ;
}
//  main.c
// Created by weichen on 15/6/23.
// Copyright (c) 2015年 weichen. All rights reserved.
#include <stdio.h>
#include <string.h> int mycmp(const char *s1, const char *s2) {
//当做数组处理:用一个整数当做下标,遍历字符串
/*
int index = 0;
while (1) {
if(s1[index] != s2[index]) {
break;
} else if(s1[index] == '\0') {
break;
}
index++;
}
return s1[index] - s2[index];
*/ //直接用指针:指针加加,判断指针所指的值
while () {
if(*s1 != *s2) {
break;
} else if(*s1 == '\0') {
break;
}
s1++;
s2++;
}
return *s1 - *s2; //好看的写法
/*
while (*s1 == *s2 && *s1 != '\0') {
s1++;
s2++;
}
return *s1 - *s2;
*/
} int main(int argc, const char * argv[]) { /**
* strcmp
* int strcmp(const char *s1, const char *s2);
* 比较两个字符串,返回:
* 0 :s1==s2
* 1 :s1 >s2
* -1:s1 <s2
*/ char s1[] = "abc"; char s2[] = "abc "; printf("%d\n", strcmp(s1, s2)); // printf("%d\n", mycmp(s1, s2)); //判断两个字符串是否相等的写法
if(strcmp(s1, s2) == ) {
printf("s1 = s2");
} else {
printf("s1 != s2");
} return ;
}
//  main.c
// Created by weichen on 15/6/23.
// Copyright (c) 2015年 weichen. All rights reserved. #include <stdio.h>
#include <string.h> char* mycmp(char *dst, const char *src) {
/*
数组方式
int index = 0;
while(src[index] != '\0') {
dst[index] = src[index];
index++;
}
//src所有的字符串复制完后,dst还差一个结尾的0,需要加上去
dst[index] = '\0';
return dst;
*/ //指针方式
char* ret = dst;
while (*src != '\0') {
*dst = *src;
src++;
dst++;
}
*dst = '\0';
return ret;
} int main(int argc, const char * argv[]) {
/**
* strcpy
* char * strcpy(char *restrict dst, const char *restrict src);
* 把src的字符串拷贝到dst,restrict表明src和dst不重叠(C99)
* 返回dst,为了能链起代码来
*/ /*
复制一个字符串的套路
char *dst = (char*)malloc(strlen(src) + 1); //不知道要复制的字符串占多大空间,所以需要动态分配内存,strlen只能求出字符串的大小,不包含结尾的0
strcpy(dst, src);
*/
  
   char s1[] = "abc";
   char *str = (char*)malloc(strlen(s1) + 1);
strcpy(str, s1);
   printf("%s", str);
return ;
}
//  main.c
// Created by weichen on 15/6/26.
// Copyright (c) 2015年 weichen. All rights reserved.
#include <stdio.h>
#include <string.h>
#include <stdlib.h> int main(int argc, const char * argv[]) {
/*
在字符串中找单个字符
char* strchr(const char *s, int c);
char* strrchr(const char *s, int c);
返回NULL表示没有找到
*/ char s[] = "hello";
char *p = strchr(s, 'l');
printf("%s\n", p); //llo //找第二个l
char *q = strchr(p + , 'l');
printf("%s\n", q); //lo //从右边开始找
char *a = strrchr(s, 'l');
printf("%s\n", a); //lo //复制找到的字符串
char *r = (char*)malloc(strlen(p) + ); //1.动态分配内存空间
char *t = strcpy(r, p); //2.复制字符串
printf("%s\n", t); //llo
free(r); //3.释放动态分配的内存空间 //找l之前字符的技巧
char c = *p;
*p = '\0'; //将*p所指的位置替换为\0; s就变成了he\0lo
char *u = (char*)malloc(strlen(s) + );
char *v = strcpy(u, s);
printf("%s\n", v); //he
printf("%s\n", s); //he
free(u); //最后将*p恢复为l
*p = c;
printf("%s\n", s); //hello /*
字符串中找字符串
char* strstr(const char *s1, const char *s2);
字符串中找字符串,并忽略大小写
char* strcasestr(const char *s1, const char *s2);
*/
char x[] = "E";
char y[] = "e";
char *z1 = strstr(s, x); //如果第二个参数x改为字符'E',就会报错,因为函数接受的参数是一个指针;
char *z2 = strstr(s, y);
char *z3 = strcasestr(s, x);
printf("%s\n", z1); //null
printf("%s\n", z2); //ello
printf("%s\n", z3); //ello /*
连接两个字符串
extern char* strcat(char *dest, char *src);
*/
char ab[] = "good";
char *cd = "bye";
strcat(ab, cd);
printf("%s\n", ab); //goodbye return ;
} //注:PHP中strchr是strstr的别名,因为里面没有指针一说,所以第一第二个参数均为字符串。

Link:http://www.cnblogs.com/farwish/p/4477897.html

上一篇:C++学习笔记(十一):void*指针、类型转换和动态内存分配


下一篇:Spring源码分析(二十四)初始化非延迟加载单例