C语言学习6 :指针的定义,指针类型要合法,指针要初始化,指针做函数参数,数组和指针的通用性,指针+1所代表的空间,void * 指针,交换函数中的指针,数组和字符型指针区别,字符型指针的应用,使用指...

1,指针的基本用法1

#include <stdio.h>

// 指针和数组都是复合类型, 他们从基本类型
// 或者自定义类型派生.

int main(void)
{
    // 当定义指针变量p 时, int * --> 这里的 *
    // 不是运算符, 而是 类型定义说明符.

    // 定义了一个变量p
    // p 是 int * 类型. p 指向 int 类型.
    int *p = NULL; 
    int a = 8;

    // 此时, p 指向 a
    p = &a;

    printf("sizeof p = %u\n", sizeof(p));
    printf("&p = %p, p = %p\n", &p, p);
    printf("&a = %p, a = %d\n", &a, a);
    printf("====================\n");

    // * 是一个运算符. 称解引用运算符 / 间接访问运算符
    *p = 16;
    printf("a = %d, *p = %d\n", a, *p);

    printf("--------------------\n");

    // [] 是一个运算符. 按索引解引用 / 按索引间接访问.
    p[0] = 32;
    printf("a = %d, *p = %d\n", a, *p);

    return 0;
}

结果:

will@will-Inspiron-N4010:~/c/5th$ ./a.out
sizeof p = 4
&p = 0xbf8b9f18, p = 0xbf8b9f1c
&a = 0xbf8b9f1c, a = 8
====================
a = 16, *p = 16
--------------------
a = 32, *p = 32

2,指针的基本用法2

#include <stdio.h>

int main(void)
{
    unsigned long p = 0;
    int a = 8;

    // &a 的结果是一个 int * 类型的指针值
    // 将其转换为 unsigned long, 去除编译器警告
    // 之后, 变量p 中存放了 变量a 的地址.
    p = (unsigned long)&a;

    // 类型决定类型之上的操作是否合法
    // 所以, 将 p 强制转换为 int * 类型,
    // 那么对 p 进行解引用运算就合法了.
    *(int *)p = 16;

    printf("a = %d, *p = %d\n", a, *(int *)p);

    return 0;
}

结果:(int *)这个是作为定义的存在,相当于int *p

a = 16, *p = 16

3,指针基本用法3

#include <stdio.h>

int main(void)
{
    // 未初始化的指针称为野指针
    // dangling pointer
    int *p;

    printf("p = %p\n", p);

    *p = 345;

    printf("*p = %d\n", *p);

    return 0;
}

结果:未初始化的指针无法直接赋值。

p = 0xb77b3ff4
Segmentation fault (core dumped)
4,指针做函数参数

#include <stdio.h>

void rand_a(int *p, int len)
{
    int i;
    for (i = 0; i < len; i++)
        // *(p + i) = rand() % 100;
        p[i] = rand() % 100;
}

void print_a(int *p, int len)
{
    int i;
    for (i = 0; i < len; i++)
        printf("%d ", *(p + i));
    putchar('\n');
}

int main(void)
{
    int a[10];

    rand_a(a, 10);

    print_a(&a[0], 10);

    return 0;
}

结果:数组传入是int a[ ],指针形式传入是int *a  都是传入数组首地址,两者可通用

will@will-Inspiron-N4010:~/c/5th$ ./a.out
83 86 77 15 93 35 86 92 49 21 

5,数组和指针的通用性

#include <stdio.h>

void rand_a(int *p, int len)
{
    int i;
    for (i = 0; i < len; i++)
        *(p + i) = rand() % 100;
}

void print_a(int *p, int len)
{
    int i;
    for (i = 0; i < len; i++)
        printf("%d ", *(p + i));
    putchar('\n');
}

int max(int *p, int len)
{
    int i;
    int max = *p;

    for (i = 0; i < len; i++)
    {
        if (*(p + i) > max)    
            max = *(p + i);
    }

    return max;
}

int min(int *p, int len)
{
    int i;
    int min = *p;

    for (i = 0; i < len; i++)
    {
        if (*(p + i) < min)    
            min = *(p + i);
    }

    return min;
}

void __move_left(int *p, int len)
{
    int i;
    int t = *p;

    for (i = 0; i < len - 1; i++)
        *(p + i) = *(p + i + 1);

    *(p + i) = t;
}

void move_left(int *p, int len, int shift)
{
    int i;
    shift %= len;
    for (i = 0; i < shift; i++)
        __move_left(p, len);
}

void __move_right(int *p, int len)
{
    int i;
    for (i = len - 1; i > 0; i--)
    {
        *(p + i) ^= *(p + i - 1);    
        *(p + i - 1) ^= *(p + i);
        *(p + i) ^= *(p + i - 1);    
    }
}

void move_right(int *p, int len, int shift)
{
    int i;
    shift %= len;
    for (i = 0; i < shift; i++)
        __move_right(p, len);
}

void reverse(int *p, int len)
{
    int i;
    for (i = 0; i < len / 2; i++)
    {
        *(p + i) ^= *(p + len - i - 1);    
        *(p + len - i - 1) ^= *(p + i);
        *(p + i) ^= *(p + len - i - 1);    
    }
}

void bubble_sort(int *p, int len)
{
    int i, j;
    for (i = 0; i < len - 1; i++)
    {
        for (j = 0; j < len - i - 1; j++)    
        {
            if (*(p + j) > *(p + j + 1))    
            {
                *(p + j) ^= *(p + j + 1);    
                *(p + j + 1) ^= *(p + j);
                *(p + j) ^= *(p + j + 1);    
            }
        }
    }
}

int main(void)
{
    int a[10];

    rand_a(a, 10);
    print_a(a, 10);

    printf("max: %d\n", max(a, 10));
    printf("min: %d\n", min(a, 10));

    printf("move left 3:\n");
    move_left(a, 10, 3);
    print_a(a, 10);

    printf("move right 3:\n");
    move_right(a, 10, 3);
    print_a(a, 10);

    printf("reverse:\n");
    reverse(a, 10);
    print_a(a, 10);

    printf("sort:\n");
    bubble_sort(a, 10);
    print_a(a, 10);

    return 0;
}

结果和前一章节的数组变换一样。只不过是p[i]  替换成*(p+i)而已,p是首地址。

6,指针在内存中的使用

#include <stdio.h>

int main(void)
{
    int *p = NULL;
    char *pch = NULL;
    int a = 0x55667788;

    p = &a;
    pch = (char *)p;

    printf("p = %p, pch = %p, &a = %p\n", p, pch, &a);

    // 指针指向的类型决定了其 + 1, 地址 + 多少字节.
    printf("p + 1 = %p, pch + 1 = %p\n", p + 1, pch + 1);

    // 同时, 指针指向的类型决定了 *p 从指针指向的地址取出多少(字节)内容.
    printf("*p          = %#x\n", *p);

    // 打印时, 隐式类型转换, 符号扩展
    printf("*pch        = %#x\n", *pch);
    printf("*pch + 1    = %#x\n", *(pch + 1));
    printf("*pch + 2    = %#x\n", *(pch + 2));
    printf("*pch + 3    = %#x\n", *(pch + 3));

    return 0;
}

结果:

will@will-Inspiron-N4010:~/c/5th$ ./a.out
p = 0xbfb39104, pch = 0xbfb39104, &a = 0xbfb39104
p + 1 = 0xbfb39108, pch + 1 = 0xbfb39105
*p          = 0x55667788
*pch        = 0xffffff88
*pch + 1    = 0x77
*pch + 2    = 0x66
*pch + 3    = 0x55

 7,void * 指针

#include <stdio.h>

int main(void)
{
    int *p = NULL;
    void *pv = NULL;

    int a = 0x11223344;

    p = &a;

    // void * 类型和任意指针类型 类型兼容
    pv = p;

    printf("p = %p, pv = %p, &a = %p\n", p, pv, &a);
    // void * 类型指针 + 1, 地址 + 1(字节).
    printf("p + 1 = %p, pv + 1 = %p\n", p + 1, pv + 1);

    printf("------------------\n");
    printf("a = %#x, *p  = %#x\n", a, *p);

    // void * 类型不允许解引用.
    printf("a = %#x, *pv = %#x\n", a, *(int *)pv);

    return 0;
}

结果:不允许直接使用*pv必须转换,所以就有了int *的定义。

p = 0xbfacdad4, pv = 0xbfacdad4, &a = 0xbfacdad4
p + 1 = 0xbfacdad8, pv + 1 = 0xbfacdad5
------------------
a = 0x11223344, *p  = 0x11223344
a = 0x11223344, *pv = 0x11223344

8,交换函数中指针的作用

#include <stdio.h>

void swap1(int a, int b)
{
    int t;
    t = a;
    a = b;
    b = t;
}

void swap2(int *a, int *b)
{
    int t;
    t = *a;
    *a = *b;
    *b = t;
}

int main(void)
{
    int a = 3, b = 5;

    printf("a = %d, b = %d\n", a, b);

    swap1(a, b);
    printf("---after swap1---\n");
    printf("a = %d, b = %d\n", a, b);

    swap2(&a, &b);
    printf("---after swap2---\n");
    printf("a = %d, b = %d\n", a, b);

    return 0;
}

结果:效果是一样的,给了地址交换。

a = 3, b = 5
---after swap1---
a = 3, b = 5
---after swap2---
a = 5, b = 3

9,数组和字符型指针的区别

#include <stdio.h>

int main(void)
{
    // 数组初始化, 字符存放在 str 数组中.
    char str[128] = "china unix";

    // 将字符串的首地址给予指针变量 s
    // 字符串本身存放于 .rodata 段.
    char *s = "china unix";

    printf("str = %s\n", str);
    str[2] = 'I';
    printf("str = %s\n", str);

    printf("----------------------------\n");

    printf("s = %s\n", s);
    // 段错误.(试图修改只读数据段的数据)
    s[2] = 'I';
    printf("s = %s\n", s);

    return 0;
}

结果:数组可改,字符型指针不可更改

str = china unix
str = chIna unix
----------------------------
s = china unix
Segmentation fault (core dumped)

10,字符型指针应用

#include <stdio.h>

int main(void)
{
    char *s = "012345ABCDEF";

    printf("s[6] = %c\n", s[6]);

    printf("-----------------\n");

    printf("\"012345ABCDEF\"[6] = %c\n", "012345ABCDEF"[6]);
    printf("*(\"012345ABCDEF\" + 6) = %c\n", *("012345ABCDEF" + 6));

    return 0;
}

结果:其实效果一样

s[6] = A
-----------------
"012345ABCDEF"[6] = A
*("012345ABCDEF" + 6) = A

11,使用指针完成字符操作函数

#include <stdio.h>

int my_strlen(char *s)
{
    int i = 0;

    while (*(s + i) != '\0')
        i++;
    return i;
}

int my_strlen_recur(char *s)
{
    if (*s == '\0')
        return 0;

    return 1 + my_strlen_recur(++s);
}

char *my_strcpy(char *dst, const char *src)
{
    char *dst_old = dst;

    while ((*dst++ = *src++) != '\0')
        ;
    return dst_old;
}

char *my_strcat(char *dst, const char *src)
{
    char *dst_old = dst;

    /*
     * dst --> '\0'后一字符
     * while (*dst++ != '\0')
     *    ;
     */

    // dst --> '\0'
    while (*dst != '\0')
        dst++;

    while ((*dst++ = *src++) != '\0')
        ;

    return dst_old;
}

int my_strcmp(const char *s1, const char *s2)
{
    while (*s1 == *s2 && *s1 != '\0')
        s1++, s2++;

    return *s1 - *s2;
}

char *my_strchr(const char *s, int c)
{
    while (*s != '\0')
    {
        if (*s == c)    
            return (char *)s;
        s++;
    }

    return NULL;
}

char *my_strstr(const char *s, const char *substr)
{
    const char *start_cmp = NULL, *substr_start = substr;

    while (*s != '\0')
    {
        start_cmp = s, substr = substr_start;
        while (*s == *substr && *s != '\0')
            s++, substr++;

        if (*substr == '\0')
            return (char *)start_cmp;

        s = start_cmp;
        s++;
    }

    return NULL;
}

int main(void)
{
    char s1[128];
    char s2[128];

    printf("test strlen, input s1:");
    gets(s1);
    printf("len of s1 is %d\n", my_strlen(s1));

    printf("test strcpy, input s1: ");
    gets(s1);
    my_strcpy(s2, s1);
    printf("s2: %s\n", s2);

    printf("test strcat, input s1: ");
    gets(s1);
    my_strcat(s2, s1);
    printf("s2: %s\n", s2);

    printf("test strcmp, input s1: ");
    gets(s1);
    printf("test strcmp, input s2: ");
    gets(s2);
    if (strcmp(s1, s2) > 0)
        printf("%s > %s\n", s1, s2);
    else if (strcmp(s1, s2) < 0)
        printf("%s < %s\n", s1, s2);
    else
        printf("%s == %s\n", s1, s2);

    int ch;
    char *index = NULL;
    printf("test strchr, input s1: ");
    gets(s1);
    printf("input ch: ");
    ch = getchar();
    if ((index = my_strchr(s1, ch)) != NULL)
        printf("%s has %c, index = %d\n", s1, ch, index - s1);
    else
        printf("not find.\n");

    while (getchar() != '\n')
        ;

    printf("test strstr, input s1: ");
    gets(s1);
    printf("input s2: ");
    gets(s2);
    if ((index = my_strstr(s1, s2)) != NULL)
        printf("%s has %s, index = %d\n", s1, s2, index - s1);
    else
        printf("not find.\n");

    return 0;
}

结果:

test strlen, input s1:wang
len of s1 is 4
test strcpy, input s1: apk
s2: apk
test strcat, input s1: apk
s2: apkapk
test strcmp, input s1: what
test strcmp, input s2: whaa
what > whaa
test strchr, input s1: what
input ch: a
what has a, index = 2
test strstr, input s1: what2222at
input s2: at
what2222at has at, index = 2

 

转载于:https://www.cnblogs.com/will-boot/p/3301402.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值