03C语言基础-指针

C语言基础-指针

1.简介

什么是指针,指针就是内存地址,32位占用4字节,64位占用8字节,指针变量是用来存放内存地址的变量。

简单理解:指针4字节或8字节的内存空间,用于存储内存地址。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JA50x4gM-1625062971571)(G:\markdown\C++\一级指针.PNG)]

通过上面图,我们可以得出以下结论:

1.p指针所指向的地址发生改变,并不会影响到之前指向的地址

2.p所指向的地址数值发生改变,则所指向的地址数据也会变化, 因为是同一个地址。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    int a = 10;
    int *p;
    p = &a;
    printf("%p\n", p); //在内存中的地址
    printf("%d\n", *p);//一级指针取值
    system("pause");
    return 0;
}

2.NULL指针

#include <stdio.h>
 #include <stdlib.h>
int main ()
{
   int  *ptr = NULL;
 
   printf("ptr 的地址是 %p\n", ptr  );
   system("pause");
   return 0;
}

NULL指针,是不被允许修改数值的地址,0-255地址都不允许,因为有特俗意义。

空指针判断

if (!ptr)   空指针,则完成
if (ptr)    非空,则完成

3.多级指针

什么是多级指针,多级指针,指针其实本质还是地址,只过,多级指针,首先指向了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WQwlm49A-1625062971579)(G:\markdown\C++\二级指针.PNG)]

p5指针  int***** p5 ,获取p4 *p5,一级一级往上解析
#include <stdlib.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    int a =100;
    int *p1 = &a;
    int **p2 = &p1;
    int ***p3 = &p2;
    printf("%d, %d, %d, %d\n", a, *p1, **p2, ***p3);
    printf("&p2 = %#X, p3 = %#X\n", &p2, p3);
    printf("&p1 = %#X, p2 = %#X, *p3 = %#X\n", &p1, p2, *p3);
    printf(" &a = %#X, p1 = %#X, *p2 = %#X, **p3 = %#X\n", &a, p1, *p2, **p3);

    system("pause");
    return 0;
}
#include <stdio.h>
 #include <stdlib.h>

int main(int argc, char const *argv[])
{
    int a = 10;
    int* p1;
    p1 = &a;
    int** p2 =&p1;
    printf("%p\n",p2);
    printf("%p\n",*p1);
    printf("%p\n",*p2);
    printf("%d\n",**p2);
    system("pause");
    return 0;
}

4.指针和数组

1.数组
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    int arr[5] = {1,2,3,4,5};
    int* p = NULL;
    p = arr;
    printf("%p\n",arr);
    printf("%p\n",p);
    printf("%d\n",sizeof(arr));
    system("pause");
    return 0;
}

arr:表示指向第一个地址,但是内存空间却是整个数组大小

​ arr等价: &arr[0], arr + 0

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    int arr[5] = {1,2,3,4,5};
    int* p = NULL;
    p = arr;
    printf("%p\n",arr);
    printf("%p\n",&arr[0]);
    printf("%p\n",arr + 0);
    printf("%p\n",p);
    printf("%d\n",sizeof(arr));
    system("pause");
    return 0;
}

2.数组和p之间的区别

1.p:是一个指针,代下为4字节或8字节

2.arr是一个数组,20字节

#include <stdlib.h>
#include <stdio.h>

void Bubble2(int* arr,int length);
void Bubble(int arr[], int length);

int main(int argc, char const *argv[])
{
    int arr[] = {1, 2, 3, 4, 5};
    printf("%d\n", sizeof(arr)); //20字节
    Bubble(arr, 5);
    Bubble2(arr,5);
    system("pause");
    return 0;
}

//arr是指向0的地址,而不是数组,不拷贝,4字节或8字节
void Bubble(int arr[], int length)
{
    printf("%d\n", sizeof(arr));
}


void Bubble2(int* arr,int length)
{
    printf("%d\n", *arr);
}
3.void*万能指针

void*万能指针,可以指向任何类型的指针,但是最后使用时,一定要强转回来

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    int a = 10;
    void* p = &a;
    printf("%d\n",*(int*)p);
    system("pause");
    return 0;
}

4.const常量,常量指针

1.修饰常量,数据值不能改变,但是指针可以见解取改变, C++中不能

下面案例,会提示你有错,但是可以运行, a的值为20

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char const *argv[])
{
    const int a = 10;
    //改变a的值
    // a = 20; //报错,a指定了自身数据不能变化
    int *p;
    p = &a;
    *p = 20; //a的值发生变化
    printf("%d\n", a);
    system("pause");
    return 0;
}

2.修饰指针类型,指针可以变化,常量指针

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char const *argv[])
{
    int a = 10;
    const int *b = &a;
    int c = 20;
    b = &c;
    printf("%d\n", a);
    printf("%d\n", *b);
    system("pause");
    return 0;
}

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char const *argv[])
{
    int a = 20;
    const int *b = &a;
    a = 30;
    printf("%d\n", *b);
    system("pause");
    return 0;
}

——————修饰指针类型,代表自身不能修改内存空间值,但是指针可以发生改变

3.修饰指针, 指针常量

#include <stdlib.h>
#include <stdio.h>
int main(int argc, char const *argv[])
{
    int a = 10;
    int* const p = &a;
    *p = 30;
    int c = 40;
    //p = &c; //报错,p指针不能指向其他指针
    printf("%d\n", *p);
    system("pause");
    return 0;
}

——————const修饰指针,代表,改指针不能改变,但是内存空间值是可以改变的

4.即修饰指针类型又修饰指针

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char const *argv[])
{
    int a = 10;
    const int* const p = &a;
    //*p = 30; // 报错
    int c = 40;
    //p = &c; //报错,p指针不能指向其他指针
    printf("%d\n", *p);
    system("pause");
    return 0;
}

——————代表p指针重新指向其他指针,又不能修改内存空间,但是不代表不能其他方式不能修改

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char const *argv[])
{
    int a = 10;
    const int *const p = &a;
    //*p = 30; // 报错
    int c = 40;
    //p = &c; //报错,p指针不能指向其他指针
    printf("%d\n", *p);

    int **p2 = &p;
    *p2 = &c;
    printf("%d\n", **p2);
    system("pause");
    return 0;
}

——————没有提示错误,但是当前编译器编译时,会报错,p不能修改了,与C++一致

——————在c语言中,以前编译器,二级指针是可以修改一级指针的。

4.指针运算

指针每次+1,都是一个类型的字节,比如int,4字节,float,8字节

5.指针数组
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    int a = 1;
    int b = 2;
    int c = 3;
    int* arr[] = {&a,&b,&c};
    for (size_t i = 0; i < 3; i++)
    {
        printf("%d\n",*arr[i]);//arr[i]拿到&a, *取值,a
        printf("%d\n",*(*(arr+i)));//等价于上面,简单说
    }
    

    system("pause");
    return 0;
}

*arr = arr[0]

第二种,指针二维数组

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    int a[] = {1,2,3};
    int b[] = {4,5,6};
    int c[] = {7,8,9};
    //这种指针数组,是特殊的二维数组
    int * arr[] = {a,b,c};
    for (size_t i = 0; i < 3; i++)
    {
        for (size_t j = 0; j < 3; j++)
        {
            printf("%d\n", arr[i][j]);
            printf("%d\n", *(arr[i] + j));//arr[i]获取到a,但是会变成的a的首地址,a+j,获取a数组的地址,*取值
            printf("%d\n",*(*(arr+i) + j));//等价于上面
        }
        
    }
    system("pause");
    return 0;
}

———————简单总结:凡是看到arr数组的使用,都是首地址,只是字节大小为数组的大小

6.字符串

在c/c++语言中,是没有字符串的,字符串是通过char数组来实现的。

1.字符数组和字符串数组以及指向字符串的指针

#include <stdio.h>
#include <stdlib.h>

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

    char arr2[] = {'1','2','\0'};
    //字符数组,结尾需要加上'\0',否则就是普通数组
    char arr[] = {'a', 'b', 'c', '\0'};
    int size = sizeof(arr);
    printf("%d\n", size); // 结果是4,而不是3
    printf("%s\n", arr);  //结果是abc

    // arr = arr2; //错误,arr不能改变

    //字符串数组,默认会在最后加上\0
    char str1[] = "abc";
    printf("%s\n", str1);
    printf("%d\n",sizeof(str1));

    //指向字符串的指针
    char *str2 = "helloWorld";//
    printf("%s\n", str2);
    printf("%c\n",*str2); //h

    str2 = arr2;//可以改变指向
    printf("%s\n",str2);//12
    system("pause");
    return 0;
}

理解以下三个问题:

1.arr/str1,指向首地址,但是内存空间是整个数组,打印字符串时,会遍历拿到所有字符

  1. char *str2,代表地是,str2指向字符串字面值地指针(内存空间 其实真正的意义是 str2 =“abc” = 0x3000(假设地址);),

    记住,它是与字符串数组,概念是完全不同地,有以下不同点

    str1[],str1为数组名,整个数组内存空间,str2为变量,指针,4字节或8字节大小

    str2可以在程序执行期间指向其他字符串, str1不行

    str2不能修改字符串常量, str1可以

    #include <stdio.h>
    #include <stdlib.h>
    
    void modifyChar(char *arr);
    int main(int argc, char const *argv[])
    {
        char str[] = "helloWorld";
        modifyChar(str);
        printf("%s\n", str);
    
        //
        char* str2 = "nihao";
        // *str2 = 'a';//错误
        printf("%c\n",*str2);
    
        system("pause");
        return 0;
    }
    void modifyChar(char *arr)
    {
        while (*arr != '\0')
        {
            *arr = 'a';
            arr++;
        }
    }
    

总结: C语言中操作字符串是通过它在内存中的存储单元的首地址进行的,这是字符串的终极本质。。

7.字符串作为参数

char* 不能修改字面值常量

char arr[]可以修改字面值常量

1.字符串作为参数,会被将为指针,指向首地址,这样是避免了传递过程中,占用内存空间过大

2.char*字符串,不能修改字面值常量,但是可以指向其他地址

3.char[] 可以修改自己的值,但是不能指向其他指针

#include <stdio.h>
#include <stdlib.h>
void BubbleChar(char *arr);
void BubbleChar2(char *arr);
void BubbleChar3(char *arr);
int main(int argc, char const *argv[])
{
    // char *arr = "helloworld";
    // BubbleChar(arr);

    char arr2[] = "wodeshijie";
    BubbleChar2(arr2);
    printf("%s\n", arr2);

    char arr3[] = "zhongguo";
    BubbleChar3(arr3);
    printf("%s\n", arr3);
    system("pause");
    return 0;
}

void BubbleChar(char *arr)
{
    while (*arr != '\0')
    {
        printf("%c\n", *arr);
        arr++;
    }
}

void BubbleChar2(char *arr)
{
    char arr3[] = "nihao";
    arr = arr3;
}

void BubbleChar3(char *arr)
{
    char *arr4 = "buhao";
    arr = arr4;
}

总结:证明数组作为参数,实际是降为指针。

优点:节省内存空间

8.strlen测量长度
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *changeBubble(char *arr1, char *arr2);
int main(int argc, char const *argv[])
{
    char *arr1 = "abc";
    char *arr2 = "def";
    changeBubble(arr1, arr2);

    int length = strlen(arr1);
    printf("%d\n", length);
    system("pause");
    return 0;
}

void *changeBubble(char *arr1, char *arr2)
{
    int length = strlen(arr1);//strlen会遍历,知道找到'\0'的字符结束
    printf("%d\n", length);
}
5.拼接字符串
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *changeBubble2(char *arr1, char *arr2);
char* join3(char *s1, char *s2)  ;
int main(int argc, char const *argv[])
{
    char *arr1 = "abc";
    char *arr2 = "def";
    char *result = changeBubble2(arr1, arr2);
    printf("%s\n", result);
    free(result);//清空内存
    result = NULL;
    system("pause");
    return 0;
}

char *changeBubble2(char *arr1, char *arr2)
{
    char *result = (char *)malloc(strlen(arr1) + strlen(arr2) + 1); //1作为结束位置'\0'
    if (result == NULL)
    {
        exit(1);
    }
    char *temp = result; //记录首地址
    while (*arr1 != '\0')
    {
        *result = *arr1;
        arr1++;
        result++;
    }
    while (*arr2 != '\0')
    {
        *result = *arr2;
        arr2++;
        result++;
    }
    return temp;
}
  
/*方法三,调用C库函数,*/  
char* join3(char *s1, char *s2)  
{  
    char *result = (char*)malloc(strlen(s1)+strlen(s2)+1);//+1 for the zero-terminator  
    //in real code you would check for errors in malloc here  
    if (result == NULL) exit (1);  
  
    strcpy(result, s1);  
    strcat(result, s2);  
  
    return result;  
} 

————————总结:C语言中,C语言:字符串以“\0”结束

C++/JAVA:系统通过定义字符串长度来判断字符串是否结束,因此并不以“\0”作为结束的标志

5.字符串操作

1)字符串操作
strcpy(p, p1) 复制字符串
strncpy(p, p1, n) 复制指定长度字符串
strcat(p, p1) 附加字符串
strncat(p, p1, n) 附加指定长度字符串
strlen§ 取字符串长度
strcmp(p, p1) 比较字符串
strcasecmp忽略大小写比较字符串
strncmp(p, p1, n) 比较指定长度字符串
strchr(p, c) 在字符串中查找指定字符
strrchr(p, c) 在字符串中反向查找
strstr(p, p1) 查找字符串
strpbrk(p, p1) 以目标字符串的所有字符作为集合,在当前字符串查找该集合的任一元素
strspn(p, p1) 以目标字符串的所有字符作为集合,在当前字符串查找不属于该集合的任一元素的偏移
strcspn(p, p1) 以目标字符串的所有字符作为集合,在当前字符串查找属于该集合的任一元素的偏移

  • 具有指定长度的字符串处理函数在已处理的字符串之后填补零结尾符

2)字符串到数值类型的转换
strtod(p, ppend) 从字符串 p 中转换 double 类型数值,并将后续的字符串指针存储到 ppend 指向的 char* 类型存储。
strtol(p, ppend, base) 从字符串 p 中转换 long 类型整型数值,base 显式设置转换的整型进制,设置为 0 以根据特定格式判断所用进制,0x, 0X 前缀以解释为十六进制格式整型,0 前缀以解释为八进制格式整型
atoi§ 字符串转换到 int 整型
atof§ 字符串转换到 double 符点数
atol§ 字符串转换到 long 整型

3)字符检查
isalpha() 检查是否为字母字符
isupper() 检查是否为大写字母字符
islower() 检查是否为小写字母字符
isdigit() 检查是否为数字
isxdigit() 检查是否为十六进制数字表示的有效字符
isspace() 检查是否为空格类型字符
iscntrl() 检查是否为控制字符
ispunct() 检查是否为标点符号
isalnum() 检查是否为字母和数字
isprint() 检查是否是可打印字符
isgraph() 检查是否是图形字符,等效于 isalnum() | ispunct()

4)函数原型
原型:strcpy(char destination[], const char source[]);
功能:将字符串source拷贝到字符串destination中
例程:
#include <iostream.h>
#include <string.h>
void main(void)
{
  char str1[10] = { “TsinghuaOK”};
  char str2[10] = { “Computer”};
  cout <<strcpy(str1,str2)<<endl;
}

9.常见字符串操作

1.字符串是否相等
strcmp(str_1, str_2) == 0
2.字符串复制
strcpy(s1, s2); //复制字符串 s2 到字符串 s1。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    char *s = (char*)"helloworld";
    char *s2 = (char *)malloc(strlen(s) + 1);
    strcpy(s2, s); //复制
    printf("%s\n", s2);
    system("pause");
    return 0;
}

3.拼接
strcat(p, p1)//p1拼接到p上
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    char *firstName = "hello";
    char *secondName = "world";
    int length = strlen(firstName);
    int length2 = strlen(secondName);
    printf("%d\n", length);
    printf("%d\n", length2);
    char *name = (char *)malloc(length + length2);//1可加可不加,默认会在结尾添加一个'\0'
    strcpy(name, firstName);
    strcat(name, secondName);
    printf("%s\n", name);
    printf("%c\n", *name);
    int length3 = strlen(name);
    printf("%d\n", length3);
    while (*name != '\0')
    {
        printf("%c\n", *name);
        name++;
    }
    system("pause");
    return 0;
}
4.截取字符串

1.复制截取

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

int main(int argc, char const *argv[])
{
    char *s = "helloworldnihaoma";
    int n = 10;
    char s2[10];
    strncpy(s2, s, 10);
    printf("%s\n", s2);
    system("pause");
    return 0;
}

2.strstr

定义:strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL。

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

int main(int argc, char const *argv[])
{
    char *s1 = "helloworld";
    char *s2 = "wo";
    char *s3; //与malloc区别,就是在于malloc需要手动回收,在函数中使用时,经常不能声明,而是使用malloc
    s3 = strstr(s1, s2);
    printf("%s\n", s3);
    system("pause");
    return 0;
}

result: world; 则该函数返回str2在str1中首次出现的地址

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

int main(int argc, char const *argv[])
{
    char *s1 = "helloworld";
    char *s2 = "w0w";
    char *s3; //与malloc区别,就是在于malloc需要手动回收,在函数中使用时,经常不能声明,而是使用malloc
    s3 = strstr(s1, s2);
    printf("%s\n", arr);
    while (s3 == NULL)
    {
        printf("s3为null");
        break;
    }

    printf("%s\n", s3);
    system("pause");
    return 0;
}

result:如果没有找到,返回NULL

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值