[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 = 5;
    int b = 6;
    swap(&a, &b);
    printf("a=%d,b=%d\n", a, b);

    int c[] = {1,2,3,4,5,9,30,13,45,59};
    int min,max;
    minmax(c, sizeof(c)/sizeof(c[0]), &min, &max);
    printf("min=%d, max=%d\n", min, max);

    int d = 19;
    int e = 3;
    int f;
    if(divide(d, e, &f)) {
        printf("%d/%d=%d\n", d, e, f);
    }

    int i = 8;
    int *p;
    int k;
    k = 12;
    *p = 12;//未初始化变量,直接给指针赋值;一旦指针所指的位置不可写,程序将报错
    printf("&i=%p\n", &i);//Segmentation fault

    return 0;
}

//交换两个值
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[0];
    for(i=0; 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 = 1;
    if(e == 0) {
        ret = 0;
    } 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 0;
}

指针的计算:

/**
 * main.c
 */
#include <stdio.h>

int main(void)
{
    char ac[] = {0,1,2,3,4,5,6,};    //char数组
    char *p = ac;     //*p指向数组的第一个单元
    printf("p = %p\n", p);            //p = 0x7fff51f1dc15
    printf("p + 1 = %p\n", p + 1);    //p + 1 = 0x7fff51f1dc16

    int ai[] = {0,1,2,3,4,5,6,};   //int数组
    int *q = ai;    //*p指向数组的第一个单元
    printf("q = %p\n", q);             //q = 0x7fff50160bf0
    printf("q + 1 = %p\n", q + 1);     //q + 1 = 0x7fff50160bf4

    printf("sizeof(char)=%ld\n", sizeof(char));    //1
    printf("sizeof(int)=%ld\n", sizeof(int));    //4

    /*
     指针的计算:
         在指针上加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!=-1) {
        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 0;
}

动态内存分配:

//  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=0; i<number; i++) {
        scanf("%d", &a[i]);
    }
    for (i=number; i>=0; i--) {
        printf("%d", a[i]);
    }

    free(a);    // 归还内存

    return 0;
}
/** * main.c */
#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char * argv[]) {
    // malloc:如果空间申请失败则返回0或者NULL

    void *p = 0;    //free可以释放0或NULL,避免free的地址没有被分配时出错,习惯初始化指针为0
    int cnt = 0;
    // 如果p的地址不是0(得到了地址),循环继续
    while( (p = malloc(100*1024*1024)) ) {
        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 0;
}

字符串操作:

/**
 *  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 0;

    /*
     字符串数组:
     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 = 0;
    //知道长度用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 0;
}
//  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 (1) {
        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)); //0

    printf("%d\n", mycmp(s1, s2));

    //判断两个字符串是否相等的写法
    if(strcmp(s1, s2) == 0) {
        printf("s1 = s2");
    } else {
        printf("s1 != s2");
    }

    return 0;
}
//  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 0;
}
//  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 + 1, ‘l‘);
    printf("%s\n", q);  //lo

    //从右边开始找
    char *a = strrchr(s, ‘l‘);
    printf("%s\n", a);  //lo

    //复制找到的字符串
    char *r = (char*)malloc(strlen(p) + 1); //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) + 1);
    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[10] = "good";
    char *cd = "bye";
    strcat(ab, cd);
    printf("%s\n", ab); //goodbye

    return 0;
}

//注:PHP中strchr是strstr的别名,因为里面没有指针一说,所以第一第二个参数均为字符串。

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

@黑眼诗人 <www.farwish.com>

时间: 2024-10-07 02:57:28

[C语言]进阶|指针与字符串的相关文章

C语言:通过指针对字符串进行拼接

// //  main.c //  Pointer_stringcat // //  Created by ma c on 15/8/2. //  Copyright (c) 2015年 bjsxt. All rights reserved. //  要求:使用指针连接字符串,并将连接后的字符串输出到屏幕上. #include <stdio.h> #include<string.h> void Pointer_stringcat(char *str1,const char *str

C语言中指针和字符串中的一些小结

<pre name="code" class="objc"><span style="font-family: Arial, Helvetica, sans-serif;">void a_A(char *str){</span> for (int i =0; *(str+i) != '\0'; i++) { if (*(str+i) >= 'a' && *(str+i) <= 'z'

字符串在内存中的存储——C语言进阶

字符串是以ASCII字符NUL结尾的字符序列.ASCII字符NUL表示为\0.字符串通常存储在数组或者从堆上分配的内存中.不过,并非所有的字符数组都是字符串,字符数组可能没有NUL字符.字符数组也用来表示布尔值等小的整数单元,以节省内存空间. C中有两种类型的字符串: 单字节字符串 由char数据类型组成的序列 宽字符串 由wchar_t数据类型组成的序列 wchar_t数据类型用来表示宽字符,要么是16位宽,要么是32位宽.这两种字符串都以NUL结尾.可以在string.h中找到单字节字符串函

苹果新的编程语言 Swift 语言进阶(四)--字符串和收集类型

一.字符串( String  )和字符类型(Character) 字符串是一种字符的带次序的收集类型(相当于数组),字符是字符串中的元素. 在Swift 语言中,字符串是编码独立的Unicode字符的组合,并提供相应方法来获取以各种Unicode呈现方式包含的字符. 1. 字符串定义和初始化 Swift 语言使用var或let关键字来定义一个常量字符串(不可修改)或变量字符串(可以修改).  而不是像Object C语言一样定义两种不同的类型. Swift 语言允许使用一个双引号的字符串来初始化

嵌入式 Linux C语言(五)——指针与字符串

嵌入式 Linux C语言(五)--指针与字符串 一.字符串简介 1.字符串声明 声明字符串的方式有三种:字面量.字符数组.字符指针. 字符串字面量是用双引号引起来的字符序列,常用来进行初始化,位于字符串字面量池中,字符字面量是用单引号引起来的字符. 字符串字面量池是程序分配的一块内存区域,用来保存组成字符串的字符序列.多次用到一个字符串字面量时,字符串字面量池中通常只保存一份副本,一般来说字符串字面量分配在只读内存中,是不可变的,但是当把编译器有关字面量池的选项关闭时,字符串字面量可能生成多个

用c语言指针处理字符串

字符串的处理方法有两种:一种方法是使用字符数组处理字符串,另一种是方法是使用字符指针处理字符串. 后一种也是c语言比较常用的方法.下面我们来看一个列子: 1 #include<stdio.h> 2 int main() 3 { 4 char a[50],*str1,*str2; 5 char b[]="I am student."; 6 str1 = a; 7 str2 = b; 8 while((*str1=*str2)!='\0') 9 { 10 str1++; 11

网易云课堂程序设计入门--C语言第七周:指针与字符串学习笔记

====================================== 第七周:指针与字符串学习笔记 网易云课堂 程序设计入门–C语言 指针与字符串 学习笔记 ====================================== 7-1指针初步 7-1-1类型大小与取地址运算 sizeof是一个运算符 给出某个变量货类型在内存中所占据的字节数 sizeof(int); sizeif(i); double变量在内存中占据的空间是int变量的两倍 { int a; a =6; prin

C语言之深入指针与字符串

<span style="font-family:KaiTi_GB2312;font-size:24px;">#include<stdio.h> #include<stdlib.h> //要使用malloc(),必须包含此库文件 void main() { char count, *ptr1, *p; ptr1 = malloc(27*sizeof(char)); ptr1[26] = 0;//字符串要加0 if (ptr1 == NULL) { p

C语言06指针进阶

1 指针的使用 1.1 问题 写一个程序,回顾指针的基本应用,然后测试空指针和野指针,再加上条件判断进行避免. 1.2 步骤 实现此案例需要按照如下步骤进行. 步骤一:指针的使用 代码如下所示: #include <stdio.h> void swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; } int main() { int a = 10; int *p = &a; printf("a = %d\n"