小白学开发(iOS)基础C_指针(2015-07-17)

 //
//  main.c
//  指针_注意
//
//  Created by admin on 15/7/17.
//  Copyright (c) 2015年 admin. All rights reserved.
//

#include <stdio.h>

void test(int *p, int *q);
void test2(int *p, int *q);
int test4(int i, int j, int *cha);
int test5(int i, int j, int *cha, int *ji);
int main(int argc, const char * argv[]) {
/*
    1. 通过指针变量来交换两个变量的值
       使用场景1:当想在某个函数里面改变外面参数的值,第一个想到的就是指针
*/
 
    int i = 10;
    int j = 20;
    int sum = 0;
    int cha = 0;
    int ji = 0;
    
    printf("i = %d, j = %d\n", i,j);
    
    sum = test5(i, j, &cha, &ji);
    
    printf("sum = %d, cha = %d, ji = %d\n", i,cha,ji);
    
    return 0;
}
/*
    正确方法,指针传递,temp是中间变量
*/
void test(int *p, int *q)   // int *p = &i   int *q = &j
{
    int temp;
    temp = *p;
    *p = *q;
    *q = temp;
}
/*
    错误方法,这里只改变了指针的指向,并没有改变实参的值
*/

void test2(int *p, int *q)
{
    int *temp;
    temp = p;
    p = q;
    q = temp;
}
/*
    错误方法,基本数据类型作为函数参数是值传递,在函数内修改形参的值不会影响到外面实参的值
*/

void test3(int p, int q)
{
    int temp = p;
    p = q;
    q = temp;     //   这里的交换不能影响到外部实参的值
}


/*
     2. 函数需要返回多个值
        使用场景2:当想某一个函数需要返回多个返回值时,可以通过传入指针的方式返回
                 即指针得到每个返回值的地址
*/

// 求两个数的和与差
int test4(int i, int j, int *cha)
{
    int sum = i + j;
    
    *cha = i - j;   //这里要计算值,指针就指向计算出的值的地址,外面就可以通过指针来访问到这个值
    
    return sum;
}

int test5(int i, int j, int *cha, int *ji)
{
    int sum = i + j;
    
    *cha = i - j;   //这里要计算值,指针就指向计算出的值的地址,外面就可以通过指针来访问到这个值
    
    *ji = i * j;
    
    return sum;
}


//
//  main.c
//  指针_和数字的关系
//
//  Created by admin on 15/7/17.
//  Copyright (c) 2015年 admin. All rights reserved.
//

#include <stdio.h>

int main(int argc, const char * argv[]) {

    return 0;
}

void tese()
{
    /*
     1. 通过指针间接遍历数组
     */
    int ages[] = {1,2,3,4,5,6,7};
    int length = sizeof(ages)/sizeof(int);
    //  首先通过普通方法遍历数组
    for (int i = 0; i < length; i++) {
        printf("ages[%d] = %d\n", i, ages[i]);
    }
    //  通过指针遍历数组
    int *p = &ages[0];
    
    for (int i = 0; i < length; i++) {
        printf("ages[%d] = %d\n", i, *(p+i));
        //  这里定义指针p,初始化为数组的第一个元素ages[0],指针变量+1是加上指针变量类型所占用的字节数,这里p+i表示:指针从ages[0]地址开始随着i的增长,开始动态指向数组的第二个、第三个。。。元素。那么在输出的时候*(p+i)就表示取出每个地址的内容,这里即间接根据数组元素地址取出来了数组的内容。
    }
    //  指针变量+1到底是+多少,是加定义指针变量时的变量类型所占用的字节数
    //  例如
    double score = 10.1;    // double类型占8个字节
    double *p1 = &score;
    printf("地址:%p", p1);
    p1 = p1 + 1;
    printf("加1后的地址:%p", p1);
}
void test2()
{
    /*
     2. 访问数组元素的三种方式
        2.1 数组名[角标];
        2.2 指针变量名[角标];   // 这里指针变量名表示的是地址,而数组名表示的是数组的第一个元素的地址,可以相互替换
        2.3 *(指针变量 + 角标);
    */
    
}
//
//  main.c
//  指针_字符串
//
//  Created by admin on 15/7/17.
//  Copyright (c) 2015年 admin. All rights reserved.
//

#include <stdio.h>

int main(int argc, const char * argv[]) {
    

      return 0;
}


void test()
{
    /*
     1. 定义字符串的两种方式
     */
    
//   1.1. 利用数组
      //  char name[10] = "abcdefg";
//      特点:字符串里面的内容是可以修改的
//      应用场景:当字符串的内容需要经常修改时候
    
//   1.2. 利用指针
      //  char *name = "asdfadsf";
//      特点:字符串里面的内容不可以修改
//      应用场景:当字符串中的内容不需要修改时可以使用指针,可以优化内存空间
    
    /*
     2. 两种定义方式的区别
     */
    
//   2.1 数组定义字符串时
        char name1[10] = "kokoko";
        char name2[10] = "kokoko";  // name1和name2是分配了不同的内存,可以通过打印变量地址验证
        printf("name1地址 = %p\n", name1);   // 这里打印地址,而数组名就是表示数组的地址,也可以使用&name[0]替代
        printf("name2地址 = %p\n", name2);
//          name1地址 = 0x7fff5fbff82e
//          name2地址 = 0x7fff5fbff824
        name1[0] = 'M';
        printf("name1改变第一个元素后:%s", name1);  // name1改变第一个元素后:Mokoko

//   2.2 指针定义字符串时
        char *name3 = "kokoko";
        char *name4 = "kokoko";
        printf("name3地址 = %p\n", name3);    // name3和name4是分配了同一块内存,可以通过打印指针验证
        printf("name4地址 = %p\n", name4);    // 这里打印的是地址,而指针就代表地址,所以可以直接打印
//          name3地址 = 0x100000f3c
//          name4地址 = 0x100000f3c
//      *name3[0] = 'M';                 // 这样的写法是错误的,指针定义的字符串不能改变其中某一个元素的值
//      printf("name3首元素改变后:%c", name3);
     /*
      3. 字符串数组的两种定义形式
      */
//    3.1 字符串数组定义一
        char name5[2][5] = {
            "kokok",
            "lplpl"
        };
        printf("%c\n", name5[1][1]);    // 这里只能通过角标打印某一个,如果要打印“kokok”字符串,需要遍历打印
//    3.2 指针数组定义
        char *name6[5] = {
            "kokok",
            "lplpl"
        };
        printf("%s\n", name6[1]);       // 这里可以通过角标打印一个字符串
}

//
//  main.c
//  指针_返回指针的函数
//
//  Created by admin on 15/7/17.
//  Copyright (c) 2015年 admin. All rights reserved.
//

#include <stdio.h>

char* test();
int main(int argc, const char * argv[]) {

    char *result =test();
    printf("%s", result);   // s% 是根据给出的地址依次向后取值知道遇到\0停止
    return 0;
}


    /*
     1. 返回指针的函数的格式
        
        返回值类型  函数名(形参类型 形参,形参类型 形参,...)
        {
     
            函数体;
        }
     */

    char* test()
    {
        char *name = "kokok";
        return name;

    }

//
//  main.c
//  指针_指向函数的指针
//
//  Created by admin on 15/7/17.
//  Copyright (c) 2015年 admin. All rights reserved.
//

#include <stdio.h>

//  注意: 函数名就是函数的地址, 数组名就是数组的地址
int sum(int i, int j);
int main(int argc, const char * argv[]) {
    
    return 0;
}

    /*
     1. 指向函数的指针定义格式
      
        void (*pointer)();
      注:
        (*pointer): 固定格式,这样写代表定义出来的指针是指向函数的指针
        左边 void: 代表指针变量pointer将来指向的函数没有返回值,当然可以有返回值类型
        右边 (): 代表指针变量pointer将来指向的函数没有形参,当然可以有
     */

    /*
     2. 指向一个没有返回值,无形参的函数
     */
//  定义函数

void test ()
{
    printf("这是测试函数!");
}

////  定义指向test函数的指针p
//
//    void (*p)();
//    p = test;   // 指针p指向函数test,函数名后千万不能写括号
//
//    *p == test;    // P 指向 test,*p就是取指针的内容,即test()
//
////  通过指针p 调用函数test
//    test();     // 直接调用
//    (*p)();     // 间接调用,P 指向 test,*p就是取指针的内容,即test()
//    p();        // 间接调用
//
//    /*
//     3. 指向一个有返回值,有形参的函数
//     */
////  定义函数

int sum(int i, int j)
{
    return i + j;
}
////  定义指向sum函数的指针q
//
//      int (*q)(int i, int j);
//
//      q = sum;   // 指针p指向函数test,函数名后千万不能写括号
//
////    *q == sum;    // P 指向 test,*p就是取指针的内容,即test()
//
////  通过指针q 调用函数sum
//      int result = sum(10, 20);   //  直接调用
//      int result1 = (*q)(10,20);  //  间接调用
//      int result2 = q (10,20);    //  间接调用
//      printf("result = %d", result);
//      printf("result1 = %d", result1);
//      printf("result2 = %d", result2);
 //
//  main.c
//  指针_指向函数的指针(练习)
//
//  Created by admin on 15/7/18.
//  Copyright (c) 2015年 admin. All rights reserved.
//

#include <stdio.h>

void upper(char *p);
void change(char *str, void (*p)(char*));

int main(int argc, const char * argv[]) {

/*
 实现功能:从键盘输入一句英文,单词之间用空格隔开,将所有单词首字母转换成大写,用回调函数实现
 */
    //   步骤:
    //  1. 提示用户从键盘输入一句英文,单词之间用空格隔开
        printf("请输入一句英文,单词间用空格隔开:\n");
    
    //  2. 接收用户输入的英文,使用 gets()函数
        char container[100];
        gets(container);
        printf("转换前:%s\n", container);
    //  3. 转换英文单词首字母为大写
        change(container, upper);
        printf("转换后:%s\n", container);
    return 0;
}
/*
 转换字母为大写的函数
 */
//  因为要改变外部实参的值,所以这里定义形参为指针,使用时候传入存储字符串的数组名,即数组的地址即可
void upper(char *p)
{
    char temp = *p;                     //  首先将指针所指的内容取出,赋值给一个变量,然后对其操作
    if (temp >= 'a' && temp <= 'z') {
        temp = temp - ('a' - 'A');      //  根据ASCII 特点将小写转换为大写
    }
    
    *p = temp;                          //  将更改后的内容重新赋值给指针指向的存储空间
}

/*
 转换整句英文格式的函数(使用回调函数)
 */
//  回调函数:将函数1以参数形式传入函数2,当函数2用到时,直接调用
//  在c语言中用到回调函数,就要想到指向函数的指针
void change(char *str, void (*p)(char*))     // void (*p)(char*) 为指向函数的指针
{
    (*p)(str);                  //  先将首字母变为大写
    while (*str != '\0') {      //  while条件判断字符串是否结束 如果指向内容为‘\0’就跳出结束
        if (*str == ' ') {      //  判断是否为空格
            str++;              //  指向空格的下一个字符
            (*p)(str);          //  调用函数,通过指向函数的指针
        }else{
            str++;
        }
    }

 //
//  main.c
//  指针_自定义字符串复制、拼接、比较
//
//  Created by admin on 15/7/18.
//  Copyright (c) 2015年 admin. All rights reserved.
//

#include <stdio.h>
#include <string.h>

char* myStrcpy(char *dest, const char *src);    // const 标注的变量为固定值,值不能通过重新赋值而改变
char* myStrcpy1(char *dest, const char *src);
char* myStrcat(char *dest, const char *src);
char* myStrcat1(char *dest, const char *src);
int myStrcmp(const char *str1, const char *str2);

int main(int argc, const char * argv[]) {

    char ages[5] = "koko";
    char name[5] = "koo";

/*
    printf("复制前 ages = %s", ages);
    myStrcpy(ages, name);
    printf("复制后 ages = %s", ages);
*/
/*
    printf("复制前 ages = %s", ages);
    myStrcpy1(ages, name);
    printf("复制后 ages = %s", ages);
*/
/*
    printf("拼接前 ages = %s", ages);
    myStrcat(ages, name);
    printf("拼接后 ages = %s", ages);
*/
/*
    printf("拼接前 ages = %s", ages);
    myStrcat1(ages, name);
    printf("拼接后 ages = %s", ages);
*/
    int result = myStrcmp(ages, name);
    printf("result = %d", result);
        return 0;
}

    /*
     1. 字符串拷贝
     */
//      1.1 系统自带 字符串拷贝函数
//          strcpy(dest, src) 和 strncpy(dest, src, len) 和 strlcpy(dest, src, len)
//          其中参数len 代表要拷贝的字符串的长度 具体区别见博客

/**
 *      1.2 自定义字符串拷贝函数(使用指针)
 *
 *  @param dest 目标容器
 *  @param src  被拷贝的字符
 *
 *  @return 拷贝后的地址
 */
char* myStrcpy(char *dest, const char *src)   // 定义俩指针,传入时数组名作为地址传入
{
    char *cp = dest;        //  定义一个指针保存字符串的首地址
    while (*src != '\0') {  //  循环遍历取出src中的所有字符
        *dest = *src;       //  将src所指向地址的值取出来赋值给dest所指向地址的值,即把src中的字符拷贝到dest中
        src++;              //  指针向后移动
        dest++;             //  指针向后移动
    }
    *dest = '\0';           //  dest所指的字符后加\0结束
    
    return cp;              //  返回字符串首地址
}

//进一步对myStrcpy优化
char* myStrcpy1(char *dest, const char *src)
{
    char *cp = dest;            //  定义一个指针保存字符串的首地址
    while ((*dest++ = *src++)); //  循环遍历取出src中的所有字符
    
    return cp;
}

    /*
     2. 字符串拼接
     */
//      2.1 系统自带 字符串拼接函数
//          strcat(dest, src) 和 strncat(dest, src, len) 和 strlcat(dest, src, len)
//          其中参数len 代表要拼接的字符串的长度 具体区别见博客

/**
 *      2.2 自定义字符串拼接函数(使用指针)
 *
 *  @param dest 目标容器
 *  @param src  被拼接的字符
 *
 *  @return 拼接后的地址
 */

char* myStrcat(char *dest, const char *src)
{
    char *cp = dest;            //    定义指针保存字符串的首地址
    while (*dest != '\0') {     //    移动dest指针到外面实参ages的字符串结尾(\0)
        dest++;
    }
    while (*src != '\0') {      //    拷贝name中的字符到ages中
        *dest = *src;
        src++;
        dest++;
    }
    *dest = '\0';               //     添加字符串结尾标识
    
    return cp;                  //     返回首地址
}

//进一步对myStrcat优化
char* myStrcat1(char *dest, const char *src)
{
    char *cp = dest;
    while (*dest)               //      移动dest指针到外面实参ages的字符串结尾(\0)
        dest++;
    
    while ((*dest++ = *src++)); //      拷贝name中的字符到ages中
    return cp;
}

    /*
     3. 字符串比较
     */
//      3.1 系统自带 字符比较函数
//          int strcmp(const char *, const char *) 和 int strncmp(const char *, const char *, size_t)
//          其中参数size_t 代表要比较的字符串的长度 。具体区别见博客

/**
 *      3.2 自定义字符串比较函数(使用指针)
 *
 *  @param str1 指向第一个要比较的字符串
 *  @param src  指向第二个要比较的字符串
 *
 *  @return 比较结果
 */
int myStrcmp(const char *str1, const char *str2)
{
    int result = *str1 - *str2;         //  俩指针通过数组名指向首元素, 首元素想减,比较是否相等
                                        //  若相减为0,说明首元素相同,即为假。
                                        //  若相减不为0,说明首元素不同,即为真
    while (!result && *str1 !='\0') {   //  !result表示:如果为真才能进入循环,即result为假,就是首元素相同,
                                        //  且此时 两个字符串中都不是结尾符\0 时进入循环
        str1++;
        str2++;                         //  指针自加向后移动
        result = *str1 - *str2;         //  继续相见判断是否跳出循环
    }
    if (result < 0) {                   //  判断 result
        return -1;
    }else if (result > 0)
    {
        return 1;
    }
    return result;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值