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, *取值,aprintf("%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,而不是3printf("%s\n", arr);  //结果是abc// arr = arr2; //错误,arr不能改变//字符串数组,默认会在最后加上\0char str1[] = "abc";printf("%s\n", str1);printf("%d\n",sizeof(str1));//指向字符串的指针char *str2 = "helloWorld";//printf("%s\n", str2);printf("%c\n",*str2); //hstr2 = arr2;//可以改变指向printf("%s\n",str2);//12system("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需要手动回收,在函数中使用时,经常不能声明,而是使用mallocs3 = 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需要手动回收,在函数中使用时,经常不能声明,而是使用mallocs3 = strstr(s1, s2);printf("%s\n", arr);while (s3 == NULL){printf("s3为null");break;}printf("%s\n", s3);system("pause");return 0;
}

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

03C语言基础-指针相关推荐

  1. C语言基础---指针数组----初始化方式常量指针数组、指针常量数组

    文章目录 1.方式一:变量的地址放入数组中 2.方式二:字符赋值 3.方式三:字符串赋值 4.为什么指针不能修改字符串.可以修改字符数组?? 5.常量指针数组----三点注意 6.指针常量数组---- ...

  2. c语言string函数的用法_C语言基础| 指针和函数

    点击蓝字关注我们 指针和函数 栈帧:当函数被调用时,系统会在stack空间上申请一块内存,用来给函数提供空间,存储形参和局部变量(定义在函数内部的变量). 当函数调用结束时,这块内存空间会被自动释放( ...

  3. c语言把结构体首地址放入指针,C语言基础———指针,结构体指针,函数指针

    指针基础 一 指针就是地址,地址就是指针.指针存储的是内存的地址. 二 指针的定义 1.&表示取址运算符,&a 可以取到 a 在内存中的地址;打印地址的占位符为(%p),printf( ...

  4. C语言基础指针知识点总结

    指针入门,这一篇文章应该就够了.如有错误或不足,还望多多指正. 文章目录 一. 基本概念 1.1 地址 1.2 指针 1.3 为什么要使用指针这个东西呢 1.4 指针变量的定义 1.4.1 `*` 1 ...

  5. C语言——基础指针篇

    说明:   本文章旨在总结备份.方便以后查询,由于是个人总结,如有不对,欢迎指正:另外,内容大部分来自网络.书籍.和各类手册,如若侵权请告知,马上删帖致歉.   QQ 群 号:513683159 [相 ...

  6. C语言基础——指针数组(指向数组的指针)

    数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element).数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存.定义数组时,一定要给出数组名,数组名可 ...

  7. C语言 函数指针和指针函数区别 - C语言零基础入门教程

    目录 一.函数指针和指针函数声明的区别 1.函数指针 2.指针函数 二.函数指针和指针函数调用的区别 1.函数指针的调用 2.指针函数的调用 三.猜你喜欢 零基础 Python 学习路线推荐 : C/ ...

  8. C语言 函数指针 - C语言零基础入门教程

    目录 一.函数指针简介 1.常规函数声明 2.函数指针声明 二.函数指针实战 三.猜你喜欢 零基础 Python 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.函数指 ...

  9. C语言 野指针 - C语言零基础入门教程

    目录 一.简介 二.野指针产生的原因 1.指针变量未初始化 2.指针释放后之后未置空 三.避免野指针产生 1.初始化时置 NULL 2.释放时置 NULL 四.猜你喜欢 零基础 C/C++ 学习路线推 ...

最新文章

  1. 重读Youtube深度学习推荐系统论文,字字珠玑,惊为神文
  2. 各浏览器对document.getElementById等方法的实现差异
  3. Java核心技术点之动态代理
  4. JavaScript实现jumpSearch跳转搜索算法(附完整源码)
  5. vuejs滚动条_vuescroll-一款基于vuejs2.x的虚拟滚动条
  6. 学习笔记:log4j.properties配置
  7. mac vim python3_VIM学习笔记 编译源码(Compile Code)-Python
  8. OpenCV的工具函数
  9. 邮政计算机网络,邮政计算机网络论文(共2018字).doc
  10. AJAX基础:JavaScript中类的实现
  11. linux几个不常用但是很有用的命令
  12. cmd mysql utf8_MySQL中UTF8编码的数据在cmd下乱码
  13. 水系图一般在哪里找得到_进展 | 水系钾离子电池研究取得重要进展
  14. 1050ti显卡安装cuda
  15. DNS的更新和ddns(动态域名解析)
  16. Z05 - 004、网站流量多维度细分(流量分析)
  17. 让手机变成电脑摄像头
  18. LFS系统安装镜像制作
  19. 河北大学计算机改408,河北大学2020年硕士研究生招生调剂办法
  20. python functools.reduce使用_Python的functools.reduce用法

热门文章

  1. 土方回填施工方案范本_基础施工方案(土方开挖、回填、混凝土)
  2. java 内存压缩_JVM之指针压缩内存如何设置
  3. MATLAB 变量和数据类型举例
  4. 蛇形矩阵(3月23日)
  5. Google Code Jam 2017 资格赛
  6. 【学习笔记】SNAT DNAT
  7. 第七章:项目成本管理 - (7.2 估算成本)
  8. 精选!必备的VSCode插件
  9. 抛硬币的两种思维方式
  10. 北京气象局回应为何不发短信预警:存技术障碍。(你信吗)