C语言关于指针的知识点

  • 指针是什么

指针是编程语言中的一个对象,利用地址,它的的值直接指向存在电脑存储器中的另一个地方的值。通过地址就能找到所需的变量单元。因此地址形象化的称为指针,通过它能找到以它为地址的内存单元。就像生活中住酒店一样,通过房间号就找到了你要住的的房间,这里的房间号就是地址,而房卡就是指针,房卡上面存有房间号。
指针是一个变量,存放内存单元的地址,存放在指针中的值都被当成地址处理

  • 一个单元的大小是一个字节,一个字节给一个对应的地址。
  • 指针的大小在32位平台上是4个字节,在64位平台上是8个字节。
  • 指针的类型
    跟变量一样,指针也有类型,如整形,浮点型等。char* 类型的指针存放char类型变量的地址,short* 类型的指针存放short类型变量的地址,int*类型的指针存放int类型变量的地址。
  • 指针±整数
#include<stdio.h>
int main()
{
   int n = 10;
   char* pc = (char*)&n;
   int* pi = &n;
   printf("%p\n",&n);
   printf("%p\n",pc);
   printf("%p\n",pc+1);
   printf("%p\n",pi+1);
   return 0;
}

总结:指针的类型决定了指针向前或者向后走一步有多大的距离,一个char或int等。
指针的解引用,char的指针解引用只能访问一个字节,int 的指针解引用能访问四个字节。

  • 指针和数组名

先看一个例子:

#include<stdio.h>
int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,0};
    printf("%p\n",arr);//数组首元素的地址
    printf("%p\n",&arr);//数组首元素的地址
    printf("%p\n",&arr[0]);//数组首元素的地址
    printf("%p\n",&arr+1);//跳过一个数组大小的地址
    return 0;
}

在这里插入图片描述
数组名和数组首元素的地址是一样的。数组名表示数组首元素的地址,因此可以使用指针来访问数组。

  • 指针运算

  • 指针±整数

  • 指针-指针(不能指针+指针)

  • 二级指针
    指针变量是变量,是变量就有地址,指针变量的地址也存在指针中,这个指针就是二级指针。

int a = 10;
int* pa = &a;
int** ppa = &pa;
a的地址存放在pa中,pa的地址存放在ppa中,pa是一级指针,ppa是二级指针。*ppa通过对ppa中的地址进行解引用,这样找到的是pa,*ppa访问就是pa,然后对pa进行解引用找到a。

区分
1. 字符指针 2. 指针数组 3. 数组指针 4. 函数指针 5. 函数指针数组 6. 指向函数指针数组的指针

  • 字符指针
    字符指针是一种指针类型位字符型char*
#include<stdio.h>
int main()
{
   char* ptr = "hello world";
   printf("%s\n",ptr);
   return 0;
}

ptr中存放的是hello world字符串的首地址,而不是存放字符串hello world,即一个常量字符串的首字符h的地址存放到指针变量ptr中。
注意:

#include <stdio.h>
 
int main()
{   
    char str1[] = "hello bit."; 
    char str2[] = "hello bit.";
    char *str3 = "hello bit.";   
    char *str4 = "hello bit.";
 
    if(str1 ==str2)        
       printf("str1 and str2 are same\n");    
    else        
       printf("str1 and str2 are not same\n");           
    if(str3 ==str4)        
       printf("str3 and str4 are same\n");    
    else        
        printf("str3 and str4 are not same\n");
        return 0;
  }

在这里插入图片描述
这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指 针。指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候 就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同。

  • 指针数组
    指针数组是一个存放指针的数组
int* arr[10];//整形指针数组
char* arr2[10];//一级字符指针数组
  • 数组指针
    数组指针是指针,能指向数组的指针。
int *p1[10];
int (*p2)[10];
//p1指的是一个存有10个整形的指针数组,p2指的是一个指向有10个整形数组的指针
//p2先和*结合,说明p2是是一个指针变量,然后指向的是一个大小为10个整形的数组,所以p2是一个指针,指向一个数组,叫数组指针。
  • 函数指针
void test()
{
   printf("hello\n");
}
void (*pfun1)();
void *pfun2();
//pfun1能存test函数的地址

两段有趣的代码:

(*(void (*)())0)();
//解释:调用0地址处的函数,该函数的参数是无参,返回类型为void
void (*signal(int,void(*)(int)))(int);
//解释 :signal是一个函数声明,函数的参数为int和一个函数指针,该函数指针指向的函数参数为int,返回类型为void;signal函数的返回类型也为函数指针,该函数指针指向的函数参数为int ,返回类型为void
  • 函数指针数组
    要把函数的地址存到一个数组中,这个数组就叫函数指针数组。
int (*parr1[10])();
//parr1先和[]结合,说明parr1是数组,数组的内容是int(*)()类型的函数指针;
int *parr2[10]();
int (*)() parr3[10];
  • 指向函数指针数组的指针
    指向函数指针数组的指针是一个指针,指针指向一个数组,数组的元素都是函数指针。
void test(const char* str)
 {    
    printf("%s\n", str); 
 }
  int main()
   { 
      //函数指针pfun 
      void (*pfun)(const char*) = test;
      //函数指针的数组pfunArr
      void (*pfunArr[5])(const char* str);
      pfunArr[0] = test;
      //指向函数指针数组pfunArr的指针ppfunArr
      void (*(*ppfunArr)[10])(const char*) = &pfunArr;
      return 0;
 }

指针和数组笔试题:

int main()
{
	int a[] = { 1, 2, 3, 4 };
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(a + 0));
	printf("%d\n", sizeof(*a));
	printf("%d\n", sizeof(a + 1));
	printf("%d\n", sizeof(a[1]));
	printf("%d\n", sizeof(&a));
	printf("%d\n", sizeof(*&a));
	printf("%d\n", sizeof(&a + 1));
	printf("%d\n", sizeof(&a[0]));
	printf("%d\n", sizeof(&a[0] + 1));
	return 0;
	}

在这里插入图片描述

int main()
{
//字符数组
	char arr[] = {'a','b','c','d','e','f'};
	printf("%d\n", sizeof(arr)); //6
	printf("%d\n", sizeof(arr+0)); //4
	printf("%d\n", sizeof(*arr)); //1
	printf("%d\n", sizeof(arr[1])); //1
	printf("%d\n", sizeof(&arr)); //4
	printf("%d\n", sizeof(&arr+1)); //4
	printf("%d\n", sizeof(&arr[0] + 1));//4
	printf("%d\n", strlen(arr));//随机值
	printf("%d\n", strlen(arr + 0));//随机值
	printf("%d\n", strlen(*arr));//错误
	printf("%d\n", strlen(arr[1]));//错误
	printf("%d\n", strlen(&arr));//随机值
	printf("%d\n", strlen(&arr + 1));//随机值
	printf("%d\n", strlen(&arr[0] + 1));//从'b'的地址开始的随机值
	return 0;
}
int main()
{
char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));//7
	printf("%d\n", sizeof(arr + 0));//4 
	printf("%d\n", sizeof(*arr));//1
	printf("%d\n", sizeof(arr[1]));//1
	printf("%d\n", sizeof(&arr));//4
	printf("%d\n", sizeof(&arr + 1));//4
	printf("%d\n", sizeof(&arr[0] + 1));//4

	printf("%d\n", strlen(arr));//6
	printf("%d\n", strlen(arr + 0)); //6
	printf("%d\n", strlen(*arr));//错误
	printf("%d\n", strlen(arr[1]));//错误
	printf("%d\n", strlen(&arr)); //6
	printf("%d\n", strlen(&arr + 1));//随机值
	printf("%d\n", strlen(&arr[0] + 1));//5
	return 0;
}
int main()
{
  char *p = "abcdef";
	printf("%d\n", sizeof(p));// 4
	printf("%d\n", sizeof(p + 1));//4
	printf("%d\n", sizeof(*p)); //1
	printf("%d\n", sizeof(p[0]));//1
	printf("%d\n", sizeof(&p));//4
	printf("%d\n", sizeof(&p + 1));//4
	printf("%d\n", sizeof(&p[0] + 1));//4

	printf("%d\n", strlen(p));//6
	printf("%d\n", strlen(p + 1));//5 
	printf("%d\n", strlen(*p)); //错误
	printf("%d\n", strlen(p[0])); //错误
	printf("%d\n", strlen(&p));//随机值
	printf("%d\n", strlen(&p + 1));//随机值
	printf("%d\n", strlen(&p[0] + 1));5
}
int main()
{
//二维数组 
	int a[3][4] = {0};
	printf("%d\n",sizeof(a)); 
	printf("%d\n",sizeof(a[0][0]));
	printf("%d\n",sizeof(a[0]));
	printf("%d\n",sizeof(a[0]+1));
	printf("%d\n",sizeof(*(a[0]+1)));
	printf("%d\n",sizeof(a+1));
	printf("%d\n",sizeof(*(a+1))); 
	printf("%d\n", sizeof(&a[0] + 1));
	printf("%d\n", sizeof(*(&a[0] + 1)));
	printf("%d\n", sizeof(*a));
	printf("%d\n", sizeof(a[3]));
	return 0;
}

在这里插入图片描述
总结:
1.数组名单独放在sizeof()内部,数组名表示整个数组,计算的是整个数组的大小。
2.&数组名,这里的数组名表示整个数组,取出的是数组的地址,&数组名+1,加的是整个数组的大小。sizeof(&数组名)是4个或8个字节。
3.除此之外所有的数组名都表示数组首元素的地址。

  • 区别sizeof与strlen

  • sizeof:
    1.计算所有变量类型占用内存的大小,单位是字节。
    2.在计算字符串时,要加上字符串后面的’\0’的大小。
    3.计算数组名的时候,计算的是整个数组的大小。

  • strlen
    1.计算的是字符串的长度大小。
    2.计算字符串长度时,以’\0’为结束标志,不计算’\0’的大小。

  • 指针中常遇到的一些陷阱

1.指针遇到运算符*和++的情况:
*和++的优先级相同,都是自右向左的顺序结合。

a = *p++ //先将指针自增,然后再取指针的内容赋给a
a = (*p)++ //取指针的内容赋值给a,然后指针再自增

2.字符串数组和指针
当指针指向字符串常量时,通过指针不能修改字符串常量的值。如:

char* p = "hello world";
p[6] = ',';//错误,这是C语言标准未定义的操作

3.利用malloc分配内存
如果将某一个字符串复制到另一个某一个控件,需要用malloc开辟足够大的空间,不能忘记’\0’也要开辟空间。
4.空指针和空字符串的差别
空指针是指向0(NULL)的指针,C语言保证对空指针的操作是安全的

char *p = NULL; //C语言定义的NULL #define NULL 0,

空字符串是只有’\0’结束符的字符串,它在内存中是有存储空间的。
注意:NULL指针并不指向任何对象,在赋值和比较运算之外的其他运算符都是非法的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值