3. 指针、数组

目录

一、指针和数组

🍐 数组名指向首地址

🍊 例子

二、数组作为函数参数 

🍋 数组名作为函数参数,为什么必须传递数组大小?

三、指针和字符数组

🍌怎么样存储一个string?

🍉数组和指针是以相似方式使用的不同类型

🍇 例子

四、指针与二维数组

🍓  数组在计算机中的组织形式

五、指针与多维数组

🍈 例子

六、数组通过指针动态分配内存

🍟 一维数组

🍕  二维数组

🥪二维数组妙用


一、指针和数组

🍐 数组名指向首地址

int *p=&A[0]
int *p=A;

🍊 例子

#include<stdio.h>
int main()
{
	int A[] ={2,4,5,8,1};
	int i;
	int *p = A;
	p++;
	// A++; // invalid!! compile error

	printf("Address &A= %lu\n", &A);
	printf("Address A= %lu\n", A);
	
	for (int i=0; i < 5; i++) {
	  printf("Address = %lu\n", &A[i]);
	  printf("Address = %lu\n", A+i);
	  printf("Value = %lu\n", A[i]);
	  printf("Value = %lu\n", *(A+i));
	}

    return 0;
}

Notes:

数组名不能自增。

输出:

Address &A= 140737488347616
Address A= 140737488347616
Address = 140737488347616
Address = 140737488347616
Value = 2
Value = 2
Address = 140737488347620
Address = 140737488347620
Value = 4
Value = 4
Address = 140737488347624
Address = 140737488347624
Value = 5
Value = 5
Address = 140737488347628
Address = 140737488347628
Value = 8
Value = 8
Address = 140737488347632
Address = 140737488347632
Value = 1
Value = 1

二、数组作为函数参数 

当数组作为函数参数时,当传入 数组名[] (A [] ) 并不会将整个数组拷贝一遍,编译器将形参的int A[ ]理解为指针,而非数组。

🍋 数组名作为函数参数,为什么必须传递数组大小?

#include<stdio.h>
// int SumOfElements(int *A)
int SumOfElements(int A[])
{
	int i,sum=0;
	int size=sizeof(A)/sizeof(A[0]);   // 这里是A被理解为一个指针,sizeof(A)=8
	
	printf( "size of A = %d,size of A[0] = %d\n",sizeof(A),sizeof(A[0]) );
 
	for(i=0;i<size;i++)
	{
		sum += A[i];
	}
	return sum;
}
 
int main()
{
	int A[] = {1,2,3,4,5};
	int total= SumOfElements(A);
	
	printf( "数组元素之和 = %d\n",total );
	printf( "size of A = %d,size of A[0] = %d\n",sizeof(A),sizeof(A[0]) );
}

输出

size of A = 8,size of A[0] = 4
数组元素之和 = 3
size of A = 20,size of A[0] = 4

改进

#include<stdio.h>
// int SumOfElements(int *A, int size)
int SumOfElements(int A[], int size)
{
	int i,sum=0;
 
	for(i=0;i<size;i++)
	{
		sum += A[i];
	}
	return sum;
}
 
int main()
{
	int A[] = {1,2,3,4,5};
	int total= SumOfElements(A, sizeof(A)/sizeof(A[0]));
	
	printf( "数组元素之和 = %d\n",total );
}

输出

数组元素之和 = 15

三、指针和字符数组

🍌怎么样存储一个string?

  • (size of array) >= (num of characters in string + 1)
  • 所有的字符串函数均假定字符串以 \0 结束
#include <stdio.h>
#include <string.h>
 
int main()
{
	char C[10];
	C[0] = 'J';
	C[1] = 'O';
	C[2] = 'H';
	C[3] = 'N';
	printf("%s\n",C);	// 打印出乱码
 
	C[4] = '\0';
	printf("%s\n",C);	// 正常打印
 
	printf("字符串长度C=%d\n\n",strlen(C));	  // \0不算入字符串长度
 
	
	char s[] = "GZC";						// 自动计算长度,字符串子面值隐含了\0
	// char s[4] = "GZC";
	// char s[4] = {'G','Z','C','\0'};

	printf("%s\n",s);
	printf("字符串长度s=%d\n",strlen(s));	// \0不算入字符串长度
	printf("size of s=%d\n",sizeof(s));	   // 将\0也计算在内
}

输出

JOHN���
JOHN
字符串长度C=4

GZC
字符串长度s=3
size of s=4

🍉数组和指针是以相似方式使用的不同类型

  • C2和C1在内存上是不一样的,一个以 \0 结尾,一个只是一个指针
  • C2=C1 is valid, C1=C2 is invalid
  • C1++也是invalid的

🍇 例子

上图的指针为4 bytes

char test[] = "hello";    //字符串存放在栈空间,可修改
char *test = "hello";    //字符串存放在只读数据区,不可修改

四、指针与二维数组

🍓  数组在计算机中的组织形式

上面这些可以通过画框法来进行理解

换算公式

五、指针与多维数组

🍈 例子

#include<stdio.h>
 
void func(int A[][2][2])
{
	printf("hello world\n");
}
 
int main()
 
{
	int C[3][2][2] = {{{2, 5}, {7, 9}},
					  {{3, 4}, {6, 1}},
					  {{0, 8}, {11, 13}}};

	printf("%lu %lu %lu %lu \n",C,*C,C[0],&C[0][0]);
	printf("%lu\n",*(C[0][0]+1));
	func(C);
	return 0;
}

输出

140737488347584 140737488347584 140737488347584 140737488347584 
5
hello world

六、数组通过指针动态分配内存

🍟 一维数组

首先,考虑一个一维数组。如果你需要创建一个包含num_elements个unsigned int的数组,你可以这样做:

unsigned int* array = new unsigned int[num_elements];

🍕  二维数组

当你需要创建一个二维数组时,情况就变得复杂了。一个二维数组可以看作是一个数组,其中每个元素都是一个数组。因此,你需要一个指针来指向这些内部数组,而每个内部数组本身也需要一个指针来指向它们的元素。

假设你想要创建一个二维数组,其中有num_rows行和num_cols列(每行包含num_cols个unsigned int元素)。你可以这样初始化它:

unsigned int** array_2d = new unsigned int*[num_rows];
for (int i = 0; i < num_rows; ++i) {
    array_2d[i] = new unsigned int[num_cols];
}

在这个例子中:

  • array_2d是一个指向unsigned int*的指针(即二级指针)。它指向一个数组,这个数组的每个元素都是一个指向unsigned int的指针(即每行都是一个unsigned int数组)。
  • array_2d[i]是一个指向unsigned int的指针(即一级指针),它指向第i行的数组。
  • array_2d[i][j]访问的是第i行第j列的元素。

🥪二维数组妙用

#include <iostream>
#include <string.h>
using namespace std;

int main() {
    unsigned int** new_table = nullptr;  
    int num_clks=5;
    int alloc_size=num_clks*(1+num_clks)>>1;  //分配一个三角形
    new_table = new unsigned int*[num_clks];  // 分配一个包含5个int*的数组  
    new_table[0] = new unsigned int[alloc_size]; // 分配一个包含15个int的数组,并使new_table[0]指向它
    
    bzero(new_table[0],alloc_size);
    for(int i=1;i<num_clks;i++)new_table[i]=new_table[i-1]+i;
    
    for(int i=0;i<alloc_size;i++)new_table[0][i]=i;
    for(int i=0;i<alloc_size;i++)cout<<new_table[0][i]<<" ";
    cout<<endl;
    
    for(int i=0;i<num_clks;i++){
        for(int j=0;j<=i;j++)cout<<new_table[i][j]<<" ";
        cout<<endl;
    }
    return 0;
}
  • 在例子中,new_table 是一个 unsigned int** 类型的变量,这意味着 new_table 是一个指向 unsigned int* 类型的指针的指针。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值