学习内容
- 什么是指针
- 指针类型
- 数组与指针
- 指针与函数
- 函数、指针、数组互用的注意事项
- 字符数组与指针
- 变量内存的分配
- 动态分配内存
- 指针demo之输入姓名
- 指针demo之比较字符
1、什么是指针
指针是一个变量,这个变量只能存地址,指针变量占据8个字节空间
作用 :如果希望在函数之间传递数据a(>1)给调用者
(1)、声明时表明是一个指针变量
(2)、使用时表示是地址内中的一个值
&:取地址
2指针类型
去掉*和变量名就是指针的类型
常量指针:常量指针不可以改变指针指向的变量的值,可以改变指向的方向int a=10; int const *p=&a; *p=20//错误,不可改变指针指向的变量的值 p=&b//正确,改变指针指向
指针常量:可以改变指针指向的变量的值,但是不可以改变指向的方向
int *const pb=&a; *p=20;//正确,改变变量的值 p=&b;//错误,不可以改变指针指向的方向 指向常量的常量指针:既不可以改变指针指向的变量的值,也不可以指针指向的方向
int const * const pc=&a;
*pc=20;//错误,不可改变指针指向的变量的值
pc=&b;//错误,不可以改变指针指向的方向
3、数组与指针
1)不同点:
a、数组名本身没有分配内存空间
b、数组名代表数组首地址
c、数组是一片连续的内存空间
d、指针只是一个变量(存地址)
e、指针变量分配的有内存空间()
f、sizeof(指针)=8,而sizeof(int型数组名)=4
2)共同点:
a、数组成员也可以通过指针去访问
b、数组是一个指针常量,所以数组的指向不能改变==不能对数组名进行运算
4、指针与函数
通过指针间接访问某个内存
定义一个函数 什么情况下参数是指针
a、这个函数会不会改变传递过来的数据本身
b、需要改变外部的值就将变量定义为一个指针变量#include <stdio.h> void test1(int *pa,int *pb){ (*pa)++; (*pb)++; } int main(){ int a=10,b=20; test1(&a,&b); printf("a=%d,b=%d",a,b); return 0; }
5函数、指针、数组互用的注意事项
函数接收数组时,必须知道数组元素个数
函数里面是通过指针变量来接收数组的地址的
指针变量无法确定指向的内容的大小
访问数组的两种方式
1、num[3]
2、*(num+3)void test2(int *p,int count(数组长度)){ for(int i=0;i<5;i++){ p[i]++;//第1种,也可以写为p[i]+=1; //*(p+i)++;第2种,也可以写为*(p+i)+=1; } } int main(){ int num[5]={1,2,3,4,5}; test2(num,5); for(int i=0;i<5;i++){ printf("%d",num[i]); } return 0; }
*#6字符数组与指针
用%s则当你在终端输入结束后在末尾默认加一个'\0',但如果用%c的话就需要在末尾手动添加一个'\0',来告诉编译器输入结束,且需要在数组中再添加一个'\0 '注意:
(1)不能直接使用字符指针来接收字符串;
(2)字符指针只为这个变量分配8个字节的内存空间,这个空间只能用来存地址不能用来存具体的数据 。例如:
#include<stdio.h> void test3(char *p){ for(int i=0;i<20;i++){ scanf("%s",p[i]); } } int main(){ char array[20]={}; //char *array; test3(array); for(int i=0;i<20;i++){ printf("%s",array[i]); } return 0; }
7变量内存的分配
常量字符串的内存空间有系统自动分配例如:"jack",在常量区里分配,当程序结束后才会被释放
常量区 - 常量 const int a=1;
静态区(生命周期很长)- static
栈 局部变量 inta=10 离开作用域就被自动收回
堆 自己申请的内存malloc calloc realloc,必须自己释放
注意:数组是变量,既可以作为局部变量也可以作为全局变量
静态变量只会被定义一次static#include<stdio.h> char* test(){ char *name = "jack"; return name; } char *test1(){ char name[10] = {'j','a','c','k'}; return name; } void test3(){ static int count=0; count++; printf("%d\n",count); } int main() { //char *p ; //p = test1(); //printf("-%s\n", p);//运行错误,因为数组是局部变量,只在test1中有效,当test1执行完后 test3(); test3(); //就会被释放,而这时候的p再去访问name的地址就属于不合法的访问 return 0; }
8动态分配内存
动态分配内存 为什么需要动态分配内存
(1)、存储的数据需要延长生命周期
(2)、一个指针变量需要存储数据,变量本身只能存地址,不能存数据,需要分配内存空间来储存数据
(3)、如果要使用指针变量接收数据,必须先为这个指针变量分配一片指向的内存空间,有空间才能存数据,所以需要导入头文件<stdlib.h>、使用malloc申请内存空间,还可以使用realloc去动态改变已经分配的内存的大小(增加后减少)[需要告诉两个参数,一个是内存所在地,一个是加或减的大小]注意:程序运行完之后必须手动释放内存,不然会导致内存泄漏
demo演示
#include<stdio.h> #include<stdlib.h> int main() { char *name; name=(char*)malloc(10*sizeof(char)); if(name==NULL){ //申请内存失败 exit(EXIT_FAILURE); } scanf("%s",name); printf("%s",name); name=(char*)realloc(name,20*sizeof(char));//由原来的的10个字节增加20个字节 if(name==NULL){ free(name); exit(EXIT_FAILURE); } free(name); return 0; }
8指针demo之比较字符串
main.cpp
#include <stdio.h> #include"myString.h" //scanf不能输入带空格的字符串 //只能自己定义一个输入语句的方法 int main(){ //1、定义两个数组保存字符串 char sentence[100]={}; char word[20]={}; //char *sdes="请输入语句"; //char *wdes="请输入查找单词"; inPut(sentence,"请输入语句"); inPut(word,"请输入查找单词"); int count=find(sentence,word); printf("%d",count); return 0; }
myString.h
#include "stdio.h" //printf(num,"请输入名称:"); void inPut(char *p,char *des); void myScanf(char *p); int find(char *sentence,char *word); int length
myString.cpp
#include "myString.h" void myScanf(char *p){ int i=0; while(1){ char c=getchar(); if(c=='\n'){ p[i]='\0'; break; } p[i]=c; i++; } } void inPut(char *p,char *des){ printf("%s:",des); myScanf(p); } int length(char *p){ int i=0; for(;p[i]!='\0';i++){ continue; } return i; } int find(char *sentence,char *word){ int sLength=length(sentence); int wLength=length(word); if(sLength<wLength){ return 0; } int start=0; int count=0; for(int i=0;i<sLength;i++){ //记录当前位置 start=i; //从当前位置取数据与查找的单词比较 int j=0; for(;j<wLength;j++){ if(sentence[start+j]!=word[j]){ break; } } if(j==wLength){ i=start+j-1; count++; } } //printf("%d %d",sLength,wLength); return count; }
指针demo之输入姓名
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> //从终端接收字符串 返回这个字符串的首地址 char *inputName(){ //1.定义一个指针变量 指向字符串的首地址 char *pName = NULL; //2.接收输入 int i = 0; //3.提示操作 printf("请输入人名:"); while (1) { //接收一个字符 char c = getchar(); //判断这个字符是不是\n if (c == '\n') { //输入结束 break; } //判断是不是第一个字符 if(i == 0){ //使用malloc分配内存 pName = (char *)malloc(1*sizeof(char)); //判断是否分配成功 if(pName == NULL){ exit(EXIT_FAILURE); } pName[0] = c; }else{ //使用realloc在之前的基础上加一个 pName = realloc(pName, (i+1)*sizeof(char)); //判断是否分配成功 if(pName == NULL){ exit(EXIT_FAILURE); } pName[i] = c; } i++; } //将当前的字符串首地址返回 return pName; } //是否继续 bool isContinue(){ printf("是否继续(y/n)?:"); while (1) { char c = getchar(); getchar(); if (c == 'y'){ return true; }else if(c == 'n'){ return false; }else{ printf("输入格式不对,请重新输入:"); } } } //初始化整个数组 char **initNames(int *pNum){ //1.定义指针变量指向每个名字的首地址的内存 char **pHead = NULL; //2.记录元素个数 int i = 0; while (1) { //判断是不是第一个 //第一个使用malloc分配内存 if (i == 0) { pHead = malloc(1*sizeof(char *)); if (pHead == NULL) { exit(EXIT_FAILURE); } //输入人名 将地址放到pHead对应位置 pHead[0] = inputName(); }else{ //使用realloc重新再增加一个元素 pHead = realloc(pHead, (i+1)*sizeof(char *)); if (pHead == NULL) { exit(EXIT_FAILURE); } //输入人名 将地址放到pHead对应位置 pHead[i] = inputName(); } i++; //是否继续 bool result = isContinue(); if (result == false) { break; } } *pNum = i; return pHead; } void show(char **pHead, int num){ printf("输入%d个名字:\n",num); for (int i = 0; i < num; i++) { printf("%s\n",pHead[i]); } printf("\n"); } int main(int argc, const char * argv[]) { char **pHead = NULL; int count = 0; pHead = initNames(&count); show(pHead, count); return 0; }