自学C语言--指针和数组···笔记

一、指针(用于存储变量的地址)

一元 & 运算符给出变量的存储地址。

注:&地址运算符   e.g. &a表示变量a的地址。

e.g.p=11;

      printf ("%d %p\n",p,&p);

注:%p 是输出地址的转换说明。

二、间接运算符:*

e.g. a=&b; c=*a;  等价于  c=b;

三、声明指针

e.g.  int *pi;     float  *p , *m;    char  *n;

(*)表明声明的变量是一个指针。声明指针变量时必须指定指针所指向的变量的类型。why?Because 不同的变量类型占用不同的存储空间,一些指针操作要求知道操作对象的大小。

四、初始化指针

在C语言中,可以通过两种方式来初始化指针:

1. 空指针初始化:将指针变量赋值为NULL,表示该指针不指向任何有效的内存地址。可以使用以下语法进行空指针初始化:

   ```
   int *ptr = NULL;
   ```

   或者

   ```
   int *ptr;
   ptr = NULL;
   ```

   注意:空指针不指向有效的内存地址,因此在使用指针之前,应该确保它不是空指针,否则可能会导致程序崩溃或未定义的行为。

2. 指向有效内存地址的指针初始化:可以将指针指向一个已经存在的变量或者动态分配的内存块。以下是两种常见的初始化方式:

   a. 指向已经存在的变量:

      ```
      int num = 10;
      int *ptr = #
      ```

      或者

      ```
      int num = 10;
      int *ptr;
      ptr = #
      ```

   b. 动态分配内存块:

      ```
      int *ptr = malloc(sizeof(int));
      ```

      注意:在使用动态分配的内存之后,应该使用`free()`函数释放它,以避免内存泄漏。

五、两个例子

date + 2 == &date [ 2 ];   //相同的地址

* (date+2)== date [ 2 ];   //相同的值

易混淆: *(date + 2) //date第三个元素的值

*date + 2  // date 第一个元素的值加二

六、函数、数组、指针

例、定义一个函数返回数组中所有元素之和。

int sum(int *ar, int n)
{
   int i;
   int total = 0;
  
   for ( i = 0; i<n;i++)
        total+= ar[i];
   return 0;
} 

注:数组名是该数组首元素的地址。e.g.  ar=&ar [ 0 ];

其中,int   *ar   等价于   int ar [  ]

#include <stdio.h>
#define SIZE 10
int sum(int ar[], int n);
int main(void)
{
    int marbles[SIZE] = {20,10,5,39,4,16,19,26,31,20};
    long answer;
    
    answer = sum(marbles, SIZE);
    printf("The total number of marbles is %ld.\n", answer);
    printf("The size of marbles is %zd bytes.\n",
           sizeof marbles);
    
    return 0;
}

int sum(int *ar, int n)     // how big an array?
{
    int i;
    int total = 0;
    
    for( i = 0; i < n; i++)
        total += ar[i];
    printf("The size of ar is %zd bytes.\n", sizeof ar);
    
    return total;
}

 等价于

#include <stdio.h>
#define SIZE 10
int sump(int * start, int * end);
int main(void)
{
    int marbles[SIZE] = {20,10,5,39,4,16,19,26,31,20};
    long answer;
    
    answer = sump(marbles, marbles + SIZE);
    printf("The total number of marbles is %ld.\n", answer);
    
    return 0;
}

/* use pointer arithmetic   */
int sump(int * start, int * end)
{
    int total = 0;
    
    while (start < end)
    {
        total += *start; // add value to total
        start++;         // advance pointer to next element
    }
    
    return total;
}

七、指针操作

1.指针赋值:用数组名、带地址运算符(&)的变量名、另一个指针进行赋值。

2.解引用:*运算符给出指针指向地址上存储的值。

3.指针与整数相加:整数会和指针所指向类型的大小(以字节为单位)相乘,然后把结果与初始地址相加。

e.g.  ptr1 + 4  等价于  & urn [ 4 ]   //其中,ptr1 是指向urn [ 0 ] 的指针

4.递增指针:递增指向数组元素的指针可以让该指针移动至数组的下一个元素。

5.指针减去一个整数:指针必须是第一个运算对象,整数是第二个运算对象。该整数将乘以指针指向类型的大小(以字节为单位),然后用初始地址减去乘积。

e.g. ptr 3 - 2 等价于 & u[2]   //其中,ptr 3 是指向u [ 4 ] 的指针

6. 递减指针:同递增指针。

7.指针求差:用于计算两个指针的差值,求差的两个指针分别指向同一个数组的不同元素,可以用于计算两元素之间的距离。差值的单位与数组类型的单位相同。  int  ptr 2 - int ptr 1  =  2  ,  2为int类型,一个int占4字节,故总的值会差4*2=8。

8.比较运算:(即:比较指针所指的地址的比较)

八、指针的基本用法

第一,在被调函数中改变主调函数的变量;

第二,保护数组中的数据。

九、用 const 保护数组的数据不被修改

e.g. int sum ( const int ar[ ] , int n );

如果编写的函数需要修改数组,在声明数组形参时,则不使用const;反之,用const。

十、const的用法

const创建变量、const创建数组、const创建指针和指向const的指针。

注:

int i
const int * p1= &i;
int const *p2= &2;    //星号在后表示指针所指向的值不能被修改
int * const p3= &3;   //星号在前表示指针不能被修改

十一、指针和多维数组

假设:int demo [4] [2];

1、demo[0] 是一个占用一个int大小对象的地址,而demo是一个占用两个int大小对象的地址。

但是,他们两个的值相同。

2、**demo 与*&demo [0] [0]等价。

十二、定义指向多维数组的指针,即:数组指针

含义:能够指向数组的指针,里面存放数组的地址。

e.g.   int array[10]={0};

int  (*p) [ 10 ] = &array;       //类型可以看成int * [ 10 ]

声明:int  (*p)[ 2 ] ;

说明:声明的是一个指向整型数组(内含两个int类型的值)的指针。p的类型是 int* [ 2 ]。

注:数组表示法vs指针表示法

int  zip[ 4 ] [ 3 ] = ~~~ ;

int (*zp) [ 2 ]  ;

zip [ m ] [ n ] == *(*(zip + m)+n) ;

zp [ m ] [ n ] == *(*(zp+m)+n) ;

十三、变长数组(允许使用变量表示数组维数)

e.g. int sum( int rows , int cols , int ar [ rows ] [ cols ] ) ;  

十四、复合字面量

字面量是除符号常量外的常量。

e.g. (int [ 2 ] ){ 10,20 };  // 其中,int [ 2 ] 是复合字面量的类型名

用法:复合字面量是匿名的,所以可以在创建的同时使用它。

e.g. int (*pt ) [ 4 ] ;  // 声明一个指向二维数组的指针,该数组内含2个数组元素

pt = (int [ 2 ] [ 4 ]) { { 1,2,3,4} { 5,6,7,8 } } ;  // 2*4 的一个数组

十五、指针数组

含义:是用来存放指针的数组。

e.g.  int * array[5];   // 存放整型指针的数组

        char * array1[5];    // 存放字符指针的数组

十六、易混淆

数组名是该数组首元素的地址,数组名与指向该数组首元素的指针等价。即:ar [ i ] 等价于 *(ar + i)。

两个等价:array=&array[ 0 ] ;

两个例外:1、sizeof (array)//里面的array是整个数组

                  2、&array // 里面的数组名是整个数组

注:&array+1是指向下一个数组的地址。

十七、一维数组传参

#include <stdio.h>

void txt(int array[])
{}

void txt(int array[10])
{}

void txt(int* array)
{}

void txt2(int *array[20]) 
{}

void txt2(int **array) 
{}

int main() {

int array[10] = {0}; 
int *array2[20]= {0}; 
txt(array);
txt2(array2); 

}

十八、二维数组传参

void test(int arr[5][6])
{}
//形参的二维数组,行可以省略,列不能省略

void test(int arr[][6])
{}

void test(int (*arr)[6])
{}

int main() {

int arr[5][6]={0};
 
test(arr);

} 

十九、函数指针

&函数名和函数名都是函数的地址。

int Add(int x,int y) 
{
return x +y; 
}
void calc(int(*pf)(int, int))
{
int a=3;
int b=5;
int ret = pf(a,b); 
printf("%d\n",ret);
}
int main()
{
calc(Add); 
return θ; 
}

与数组指针类似。

二十、函数指针数组

e.g.  int  (*p[5])(int , int) = { 0 } ;

应用:制作简易计算器。

#include <stdio.h>
int add(int x,int y)
{
	return x+y;
}

int subtract(int x, int y)
{
	return x-y;
}

int multiply(int x,int y)
{
	return x*y;
}

int divide(int x,int y)
{
	return x/y;
}

int main()
{
	int input=0;
	int x=0;
	int y=0;
	int result=0;
	int (*p[])(int,int) = {0,add,subtract,multiply,divide};
	
	printf("请输入:\n");
	scanf("%d",&input);
	while(input!=0)
	{
		if (input==0)
		  printf("退出\n");
		else if (input>0 && input<5)
		{
			printf("请输入:\n"); 
			scanf("%d %d",&x,&y);
			result=p[input](x,y);
			printf("%d\n",result);
		}
		else
		{
			printf("输入错误!");
		}
		printf("请输入:\n");
		scanf("%d",&input);
	}
	return 0;
 } 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值