当前位置:网站首页>C语言-7月21日-指针的深入

C语言-7月21日-指针的深入

2022-08-11 05:30:00 曾铎000811

目录

指针的强转问题:

const问题:

const和一级指针的结合问题:

const放在一级指针前面进行修饰(限制指针变量指向的数据):

const放在一级指针后面进行修饰(限制指针变量本身):

const对一级指针的前面和后面均进行修饰(限制指针变量和指针变量指向的数据的值):

const与二级指针结合的问题:

const放在二级指针之前:

const放在二级指针之后:

const放在二级指针之间:

作业:

作业一:利用指针实现strcpy(拷贝函数):

作业二:利用指针实现strlen(计算字符串长度)函数: 

作业三:里用指针实现strcat(链接字符串)函数:

作业四:利用指针实现strcmp(字符串比较)函数: 


今天对指针进行了更加深入地学习,回顾一下今天所讲的知识点。

指针的强转问题:

#include<stdio.h>
int main()
{
    int ar[] = {1,2,13,14};
    int *p = ar;//p指针现在是整形类型大小为4字节的指针变量
    long long *l = (long long*)p; //在这里我通过long long将p指针的大小强转位8字节
    printf("%lld",*l);
    return 0;

}

在这段代码中,我定义了一个元素个数为4的数组,定义了一个整形类型的指针变量,在下面我又通过long long对整形类型的指针变量进行强转,强制将指针的大小从原来的4字节变为8字节。我的计算机是以小端存储的方式来进行存储的,即是最低地址存放最低字节,所以数据地址的填充如下图所示:

当我执行p++语句时,语句蕴含的意思应该是:p+sizeof(p),也就是p指针每向后偏移一个单元格,所对应的字节大小应该是4,那当我执行l++语句时(l+sizeof(l)),即应该是l指针每向后偏移一个单元格,所对应的字节大小应该是8字节。

在这里先提前说明,对于栈来说,开辟内存的方式是和数组不一样的:

栈的内存开辟:从高地址向低地址进行内存开辟

数组内存开辟:从低地址向高地址进行内存开辟

在这段代码中,定义的均为局部变量,所以操作系统会在栈区进行开辟,数组包含4个整形值,栈顶指针向上偏移16个字节,与栈底指针相差16字节,这也就是ar所使用的内存区间。此时ar所指向首元素地址,位于栈顶指针所在处。

栈的分派方式

const问题:

先来了解const:const是一个C语言的关键字,const限定一个变量不允许被改变,产生静态的作用。很多时候使用const可以提高程序的安全性和可靠性。

const和一级指针的结合问题:

如果在这里我定义一个使用const修饰的值,并试图对这个值进行修改。

编译器出现了报错,因为这时max已经被const所修饰,不能被改变.

const放在一级指针前面进行修饰(限制指针变量指向的数据):

在这里我将const放在指针前面修饰,但在执行第6行代码的时候现世报错,编译器提示变量必须是可修改的左值。

下面来分析报错的原因,在const语句中,const限制了指针变量指向的数据,也就是修饰了解引用的过程。在之前的文章:指针的学习 中提到,“*”属指针的操作符,作用是引用指针指向的变量值,引用该变量的地址,然后再通过*解开,此过程称之为解引用。那么现在使用const对*p进行了修饰,也就意味着这个解引用的过程不能再变,指针p和a产生关联,p存放了a的地址,此时*p就是a本身,所以通过解引用的方式试图对a值修改的语句是会报错的。

所以可以得出结论:const修饰p的指向内容,内容不能做修改。

const放在一级指针后面进行修饰(限制指针变量本身):

现在将const放在指针后面修饰,在执行第七行代码的时候报错,编译器依旧显示变量必须是可修改的左值。

 分析报错的原因:在第5行代码中:const直接修饰了指针本身,也就是p存放a的地址的过程,此时p本身代表的就是a的地址,那么当我们试图更改p中所存放的地址时,自然就会报错了。

所以可以得出结论:当const修饰指针p本身时,指针p的值(也就是p所存放的地址)不能被修改。

const对一级指针的前面和后面均进行修饰(限制指针变量和指针变量指向的数据的值):

现在将const分别放在指针的前面和后面,执行第六行和第七行的时候编译器报错,报错原因:变量必须是可修改的左值。

分析报错的原因: 在第五行代码const对p变量本身和p变量所指向的内容均进行了修饰,也就是对解引用的过程和p存放a地址的过程均进行了修饰,所以p和*p都是不可被修改的,我们试图更改这两个值,编译器就会报错。

总结:区分const是限制指针变量本身还是指针变量所指向的值:如果const位于*号的左侧,则const用来限制指针变量所指向的值,如果const位于*号的右侧,则const用来限制指针变量本身。

const与二级指针结合的问题:

这里同样有三种结合方式:

const放在二级指针之前:

const int **q;

在这种方式下,const修饰的是int类型的,所以解引用**q等价的值是不能被赋值的,但是可以*q可以被修改地址,在这里二级指针q本身也可以被修改赋值。

const放在二级指针之后:

int **const q;

在这种方式i下,const修饰的是q二级指针本身,也就是const修饰int**类型,所以q指针是不能被修改赋值的,但是*q和**q均可以被修改赋值。

const放在二级指针之间:

int *const *q;

在这种方式下,const修饰的是*q,也就是int *类型,所以*q是不能被赋值的,但是q指针本身和**q均可以被修改赋值。 

作业:

作业一:利用指针实现strcpy(拷贝函数):

#include<stdio.h>
#include<iostream>
#include<assert.h>
void my_strcpy(int *ar,int *br,int begin_index,int m)//形参分别为:被复制的数组ar,新数组br,元素下标,数组元素个数
{
    assert(ar != nullptr && br != nullptr && begin_index >= 0);
    int *p = ar + begin_index;//p指针的初始位置是被复制数组ar的起始元素;
    int *q = br + begin_index;//q指针的位置也是br数组的起始元素;
    assert(p != nullptr && q != nullptr);
    for(int i = 0;i < m;i++){
        *q = *p;//将p指针对应的地址解引用后的元素赋值给q指针对应地址解引用的元素,循环;
        q++;
        p++;//每次赋值完之后,p指针和q指针的位置向后偏移一位,直到全部复制完成;
    }
}
int main()
{
    int m = 0;//定义整型值m用来存放被复制的数组中一共有几个元素
    printf("Please input the number of array:\n");//输入元素的个数
    scanf("%d",&m);
    int ar[m];
    printf("Please input these numbers.\n");//填充上面个数个元素
    for(int i = 0;i < m;i++){
        scanf("%d",&ar[i]);
    }
    int br[m];
    my_strcpy(ar,br,0,m);//调用函数
    printf("The array you copied br[] is:");
    for(int i = 0;i < m;i++){
        printf("%2d",br[i]);//输出
    }
    return 0;
}

例如在这里我输入元素的个数为5,填充的元素分别为:1,2,3,4,5,运行结果为:

复制完成

作业二:利用指针实现strlen(计算字符串长度)函数: 

#include<stdio.h>
#include<iostream>
#include<assert.h>
int my_strlen(char *ar)
{
    assert(ar != nullptr);
    char *p = ar;
    int m = 0;//定义整型值m来对字符串的长度进行存储
    while(*p != '\0'){//循环条件:p指针解引用后的元素不是字符串的末尾'\0'
        m++;
        p++;//每次循环记录字符串长度的m加1,p指针的位置向后迁移一位
    }
    return m;
}
int main()
{
    char message[] ="";
    printf("Please input the string.\n");
    scanf("%s",message);
    printf("The lenth of the string you put is %d",my_strlen(message));
    return 0; 
}

如图我输入fuckyou!带上感叹号一共是8个字符,我们来看一下运行结果:

结果正确,字符串长度输出成功 !

作业三:里用指针实现strcat(链接字符串)函数:

#include<stdio.h>
#include<iostream>
#include<assert.h>
void my_strcat(char *message1,char *message2)
{
    assert(message1 != nullptr && message2 != nullptr);
    char *p = message1;
    char *q = message2;
    assert(p != nullptr && q !=nullptr);
    while(*p){//此循环存在的原因:当p指针还停留在第一个字符串时,一直向后迁移,直到到达第一个字符串的末尾
        p++;
    }
    while(*q != '\0'){//跳出第一个循环之后,当指针没有到达第二个字符串的末尾时
        *p++ = *q++;//将第二个字符串的字符添加在第一个字符串的后面,循环。
    }
}
int main()
{
    char message1[100] = {0};
    char message2[100] = {0};
    printf("Please input your first string: \n");
    scanf("%s",message1);
    printf("Please input your second string: \n");
    scanf("%s",message2);
    my_strcat(message1,message2);
    printf("The string you connected is %s\n",message1);
    return 0;
}

如图为我输入的第一个字符串和第二个字传分别为Hello和world:

如图,字符串连接成功! 

字符串连接成功!

作业四:利用指针实现strcmp(字符串比较)函数: 

#include<stdio.h>
#include<iostream>
#include<assert.h>
int my_strcmp(char *p1,char *p2)
{
    assert(p1 != nullptr && p2 != nullptr);
    int i = 0;
    while(*(p1 + i) == *(p2 + i)){//循环条件为字符串1和字符串2的存在一个字符相同时
        if(*(p1 + i++) == '\0'){
            return (0);
        }
        else{
            return(*(p1 + i) - *(p2 + i));//返回值字符串1减去字符串2的ASCII码
        }
    }
}
int main()
{
    char str1[100];
    char str2[100];
    char *p1 = &str1[0];
    char *p2 = &str2[0];
    printf("Please input the strings you wanna compare:\n");
    scanf("%s%s",str1,str2);
    printf("The result of the strings you compared with is :%d ",my_strcmp(p1,p2));
    return 0;
}

如图我比较boy字符串和bad字符串,运行结果为:

结果正确 

原网站

版权声明
本文为[曾铎000811]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_45571585/article/details/125917502