c指针学习笔记(二)

目录

十、字符串和指针

十一、 数组指针

11.1 二维数组

11.2 数组指针

11.3 定义

 11.4 用途

 11.5 各种二维指针的定义

11.6  数组名字取地址 —— 数组指针

 11.7  数组名字和指针变量的区别

 11.8 多维数组中指针的转换


十、字符串和指针

字符串:字符串是以‘\0’ 结尾的若干字符的集合

字符串存储形式:数组、字符串指针、堆

char string[100] = "i love c!";
定义一个字符数组string用来存放多个字符


char *str = "i love c!";
定义一个指针变量str,只能存放字符地址编号,这个字符串的字符不能存放在str指针变量中。
str只是存放了字符1的地址编号, "i love c!"存放在文字常量区



char *str = (char *)malloc(10 * sizeof(char));
动态申请10个字节存储空间,首地址给str
strcpy(str, "i love c!")

总结: 

  • 字符数组: 在内存(栈、静态全局区)中开辟一段空间存放字符串
  • 字符串指针:在文字常量区开辟了一段空间存放字符串,将字符串的首地址付给str
  • 堆:使用malloc函数在堆区申请空间,将字符串拷贝到堆区

注意:

  • 可修改性
  1.  栈和全局区内存中的内容是可修改的 
     char str[100] = 'i love c!'; 
     str[0] = 'y';//可修改
  2. 文字 常量区的内容不可修改(尽量少使用) 
    char *str = "i love c!";  
    *str = 'y'; // 错误,存放在文字常量区,不可修改
  3. 堆区内容可以修改 
    char *str = (char *)malloc(10 * sizeof(char));
    动态申请10个字节存储空间,首地址给str
    strcpy(str, "i love c!")
    *str = 'y'; // 正确可以修改,因为堆区内容可修改
    

    注意:str 指针指向的内存能不能被修改,要看str指向那里,

    str指向文字常量区时,内存里的内容不可修改

    str指向栈、堆、静态全局区时,内存的内容是可以修改的

 初始化:

  • 字符数组、指针指向的字符串:定义时直接初始化
char buf[] = "hello world"
char *buf_point = "hello world"

  • 堆中存放的字符串不能初始化,只能使用strcpy、scanf赋值
char *buf_heap;
buf_heap = (char *)malloc(15)
strcpy(buf_heap, "hello world")
scanf("%s", buf_heap);

使用时赋值

字符数组:使用scanf或strcpy

char buf_aver[128];
buf_aver = "hello !"; // 错误,因为字符数组名字是常量
strcpy(buf_aver, "hello!"); // 正确
scanf("%s", buf_aver); // 正确

指向字符串指针:

char *buf_point;
buf_point= "hello !"; // 正确,buf_point指向另外一个字符串
strcpy(buf_point, "hello!"); // 错误,只读,能不能复制字符串到buf_point指向的内存里取决于buf_point指向哪里

十一、 数组指针

11.1 二维数组

 二维数组,有行有列。二维数组可以看成多个一维数组构成,是多个一维数组的集合,可认为二维数组的每一个元素是个一维数组。

int a[3][5];

可以将二维数组认为行指针

11.2 数组指针

数组指针是个指针,指向一个数组,加1 跳一个数组,即指向下个数组。

数组指针的作用:可以保存二维数组的首地址。

11.3 定义

指向数组类型 : (*指针变量名) [指向的数组的元素个数]

int (*p)[5];     //定义一个数组指针变量p,p指向整型的5个元素数组
p+1 往下指5个整型,跳过一个有5个整型元素的数组
#include <stdio.h> 

void test1()
{
	int a[3][5];
	int(*p)[5];
	
	printf("a = %p\n", a);
	printf("a + 1 = %p\n", a + 1);
	
	p = a;
	
	printf("p = %p\n", a);
	printf("p + 1 = %p\n", p + 1);	
} 

void main()
{

   test1();
}

 11.4 用途

//可以将二维数组的首地址传递到另一个函数里面,此时函数的形参 就需要 定义为数组指针 
void fun(int (*p)[5], int x, int y)
{
	p[0][1] = 101;
}

void test2()
{
	int i, j;
	int a[3][5] = {0};
	fun(a, 3, 5);
	
	for(i = 0; i < 3; i++)
	{
		for(j = 0; j < 5; j++)
		{
			printf(" %d  ", a[i][j]);	
		}
		printf("\n");
	}

		
} 

void main()
{

   test2();
}

 11.5 各种二维指针的定义

  • 一维数组指针,加1后指向下个一维数组
int (*p)[5];

配合每行有5个int型元素的二维数组来用

int a[3][5]
int b[4][5]
int c[5][5]
int d[6][5]
.......

p = a;
p = b;
p = c;
p = d;
  •  二维数组指针,加1后指向下个一维数组
int (*p)[4][5]

配合三维数组来用,三维数组中由若干个4行5列数组构成 

int a[3][4][5]
int b[4][4][5]
int c[5][4][5]
int d[6][4][5]
.......

p = a;
p = b;
p = c;
p = d;

 .................以此类推

  • 注意:

容易混淆的内容:

指针数组:是个数组,若干个相同类型的指针构成的集合

int *p[10];
数组p有10个int*类型的指针变量构成


数组指针:本身是个指针,指向一个数组,加1跳一个数组

int (*p)[10];
p是个数组指针,p加1 指向下个数组,跳10个整型

/
指针的指针

int **p;
int *q;
p = &q;
 

11.6  数组名字取地址 —— 数组指针

一维数组名字取地址——一维数组指针,即加1跳一个一维数组

int a[10];

a + 1 跳一个整型元素,是a[1] 的地址

a 和 a + 1 相差 一个元素, 4个字节

&a 为一个一维数组指针,是int(9p) [10]类型的

(&a) + 1 和&a 相差一个数组即10个元素即40个字节

void main()
{
	int a[10];
	
	printf("a  =%p\n", a );
	printf("a + 1 =%p\n", a + 1);
	printf("&a=%p\n", &a);
	printf("&a + 1=%p\n", &a + 1);
}

 11.7  数组名字和指针变量的区别

int a[10];
int *p;
p = a;

 相同点:

      a是数组的名字,是a[0]的地址,p = a即保存了a[0] 的地址,即 a和p都指向a[0],在引用数组元素时,a 和 p 等价

a[2], *(a + 2), p[2], *(p + 2)都是对数组a中a[2]元素的引用

不同点:

  • a是常量,p是变量 ,可以用等号“ = ”给p赋值,但不能用等号给a赋值
  • 对a 取地址,和对p取地址结果不同,因为a是数组的名字,所以对a取地址结果为数组指针,p是指针变量,所以对p取地址(&p)结果为指针的指针

 11.8 多维数组中指针的转换

在二维数组中,行地址取 * 不是取值的意思,而是指针降级意思,由行地址(数组地址)变成这一行第 0 个元素的地址。取 * 前后还是指向同一个地方,但指针的类型不一样

//二维数组的数组名降级问题 
//二维数组的数组名默认是一个行指针,加1保存下一行的首地址
//二维数组的数组名取 * ,表示地址的 降级,意味着行指针降级为列地址,加1保存下一元素的地址 

//一维数组的数组名默认是一个列指针,加1保存下一个元素的地址
//一维数组的数组名取&,则是地址的升级, 将列指针升级为行指针,加1 保存下一行元素的首地址 
void test3()
{
	int a[3][5] = {0};
	
	printf("a = %p\n", a);
	printf("a + 1 = %p\n", a + 1);
	
	printf("*a = %p\n", *a);
	printf("(*a) + 1 = %p\n", (*a) + 1);	
} 

void main()
{
	test3();
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值