学习来源 b站--作者:小甲鱼--【C语言】C语言视频教程(孤独自学 - up主)
多维数组与指针
指针变量既可以指向一维数组中的元素,也可以指向多维数组中的元素。
例如:int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}};a[0][0]的地址为2000。
表示形式 | 含义 | 地址 |
a | 二维数组名,指向一维数组a[0],即0行首地址 | 2000 |
a[0] *(a+0) *a | 0行0列元素地址 | 2000 |
a+1, &a[1] | 1行首地址 | 2016 |
a[1]+2 *(a+1)+2 &a[1][2] | 1行0列元素a[1][0]的地址 | 2024 |
*(a[1]+2) *(*(a+1)+2) a[1][2] | 1行二列元素a[1][2]的值 | 元素值为13 |
题目:输出二维数组有关的值
#include <stdio.h>
void main()
{
int a[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
printf("a: %d\n", a);
printf("*a: %d\n", *a);
printf("a[0]: %d\n", a[0]);
printf("&a[0]: %d\n", &a[0]);
printf("&a[0][0]: %d\n", &a[0][0]);
printf("a+1: %d\n", a+1);
printf("*(a+1): %d\n", *(a+1));
printf("a[1]: %d\n", a[1]);
printf("&a[1]: %d\n", &a[1]);
printf("&a[1][0]: %d\n", &a[1][0]);
printf("a+2: %d\n", a+2);
printf("*(a+2): %d\n", *(a+2));
printf("a[2]: %d\n", a[2]);
printf("&a[2]: %d\n", &a[2]);
printf("&a[2][0]: %d\n", &a[2][0]);
printf("a[1]+1: %d\n", a[1]+1);
printf("*(a+1)+1: %d\n", *(a+1)+1);
printf("*(a[1]+1): %d\n", *(a[1]+1));
printf("*(*(a+1)+1): %d\n", *(*(a+1)+1));
}
结果:
题目:通过输入指定行数和列数打印出二维数组对应任一行任一列元素的所有元素。
#include <stdio.h>
void main()
{
int a[3][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}};
int (*p)[4];
int i, j, row, colum;
scanf("%d %d",&row,&colum);
p = a;
for( i=0; i < 3; i++)
{
for( j=0; j < 4; j++)
{
if(i == row || j == colum)
{
printf("%6d", *(*(p+i)+j));
}
else
{
printf("%6c",' ');
}
}
printf("\n");
}
}
输入:1 2
结果:
题目:将字符串a复制给字符串b
解法1(下标法)
#include <stdio.h>
void main()
{
char a[] = "I love dog!", b[40];
int i;
for(i=0; *(a+i) != '\0'; i++)
{
b[i] = a[i];
}
*(b+i) = '\0';
printf("String a is: %s\n", a);
printf("String b is: ");
for(i=0; b[i] != '\0'; i++)
{
printf("%c", b[i]);
}
printf("\n\n");
}
结果:
解法2(指针方法)
#include <stdio.h>
void main()
{
char a[] = "I love dog!", b[40], *p1, *p2;
int i;
p1 = a;
p2 = b;
for( ; *p1 != '\0'; p1++, p2++)
{
*p2 = *p1;
}
*p2 = '\0';
printf("String a is: %s\n", a);
printf("String b is: ");
for(i=0; b[i] != '\0'; i++)
{
printf("%c", b[i]);
}
printf("\n");
}
结果:
字符数组和字符指针变量的区别
1.字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第1个字符的地址)。
2.对字符数组只能对各个元素赋值,不能以下方式赋值str = "I love dog.",对字符指针变量可以用a = "I love dog."的赋值方式,但是赋给a的不是字符而是字符串第一个元素的地址。
3.初始化方法不同:
//字符指针的初始化
char *a = "I love dog.";
//等价于
char *a;
a = "I love dog.";
//对数组的初始化
char str[20] = {"I love dog."};
//不能等价于
char str[20];
str[] = "I love dog.";
4.如果定义了一个字符数组,在编译时为它分配内存单元,它有确定的地址。而定义一个字符指针变量时,给指针变量分配内存单元,在其中可以放一个字符变量的地址也就是说,该指针变量可以指向一个字符型数据,但如果未对它赋予一个地址值,则它并未具体指向一个确定的字符数据。
5.指针变量的值是可以改变的,注:如果一个指针变量指向字符串可以用下标方式引用指针变量所指的字符串中的字符。
#include <stdio.h>
void main()
{
char *a = "I love dog.";
printf("%s\n", a);
a += 7;
printf("%s\n", a);
}
结果:
#include <stdio.h>
void main()
{
char *a = "I love dog.";
int i;
printf("The sixth is %c\n", a[5]);
for( i=0; a[i] != '\0'; i++ )
{
printf("%c", a[i]);
}
printf("\n");
}
结果:
指向函数的指针
题目:利用指向函数的指针完成对最大值函数使用的实现
#include <stdio.h>
int max(int x, int y)
{
int z;
if( x > y )
{
z = x;
}
else
{
z = y;
}
return z;
}
void main()
{
int max(int, int);
int (*p)();
int a, b, c;
p = max;
scanf("%d %d", &a, &b);
c = (*p)(a, b);
printf("a = %d, b = %d, max = %d\n\n", a, b, c);
}
结果:
指向函数的指针也可以作为函数的参数
void f3(int (*x1)(int),int(*x2)(int,int))
{
int a, b, i, j;
a = (*x1)(i);
n = (*x2)(i,j);
}
这个函数中,x1和x2分别是指向函数的指针变量,在调用f3函数时,实参为两个函数名f1和f2,给形参传递的是f1和f2的地址,这样函数f3中就可以调用f1和f2。
返回指针值的函数
一般定义形式:类型名 *函数名(参数列表)
题目:有若干个学生的成绩(每个学生有4门课程),要求在用户输入学生序号以后,能输出该学生的全部成绩。用指针函数来实现。
#include <stdio.h>
void main()
{
int score[3][4] = {{70,80,90,50},{90,90,90,90},{60,60,60,60}};
int *search(int (*pointer)[4],int n);
int *p;
int i,m;
scanf("%d",&m);
p = search(score,m);
for (i = 0; i < 4; i++) {
printf("%5d",*(p+i));
}
}
int *search(int (*pointer)[4],int n)
{
int *pt;
pt = *(pointer+n);
return pt;
}
输入:2
结果:
指针函数和函数指针的区别
指针函数是返回值是某一类型的指针的函数,本质是一个函数;函数指针是指向函数的指针变量,所以函数指针本身是一个指针变量。
指针数组和指向指针的指针
指针数组的每个元素均为指针类型的数据。一维指针数组的一般形式是:类型名 数组名[长度];
#include <stdio.h>
void main()
{
int a[5] = {1, 3, 5, 7, 9};
int *name[5] = {&a[0], &a[1], &a[2], &a[3], &a[4]};
int i;
for( i=0; i < 5; i++ )
{
printf("%d ", *name[i]);
}
printf("\n\n");
}
结果:
指向指针的指针的一般形式:类型名 **指针名
#include <stdio.h>
int main()
{
char *name[] = {"I love", "dog", "cat"};
char **p;
int i;
for( i=0; i < 3; i++ )
{
p = name + i;
printf("%s\n", *p);
}
}
结果:
void指针
该指针不指向一个确定的类型数据,它的作用仅仅是用来存放一个地址。
void指针可以指向任何类型数据。也就是说,,可以用任何类型的指针直接给coid指针赋值,但是,如果需要将void指针的值赋给其他类型的指针,就需要进行强制类型转换。
const指针
const char *str= "I love dog!\n\n";
//str[0] = 'w',这种方式是错误的
str = "I love cat!\n\n"; //这种方式是合法的
char * const str = "I love dog!\n\n";
str[0] = 'w' //合法
//str = "I love cat!\n\n"; 非法
const char * const str = "I love dog!\n\n";
str[0] = 'w' //非法
//str = "I love cat!\n\n"; 非法
小结
有关指针的数据类型的小结
定义 | 含义 |
int i; | 定义整型数据的指针变量 |
int *p; | p为指向整型数据的指针变量 |
int a[n]; | 定义整型数组a,它有n个元素 |
int *p[n] | 定义指针数组p,它由n个指向整型数据的指针元素组成 |
int (*p)[n] | p为指向含n个元素的一维数组的指针变量 |
int f() | f为带回整型数值的函数 |
int *p() | p为带回一个指针的函数,该指针指向整型数据 |
int (*p)() | p为指向函数的指针,该函数返回一个整型值 |
int **p | p是一个指针变量,它指向一个指向整型数据的指针变量 |
指针变量赋值
p = &a; 将变量a的地址赋给p
p = array; 将数组array首元素的地址赋给p
p = &array[i]; 将数组array的第i个元素的地址赋给p
p = max; max为已定义的函数,将max的入口地址赋给p
p1 = p2; p1和p2都是指针变量,将p2的值赋给p1
指针变量可以有空值,即该指针变量不指向任何变量,可以这样表示:p = NULL;
两个指针变量可以相减,如果两个指针变量都指向同一个数组中的元素,则两个指针变量值之差是两个指针之间的元素个数。
若两个指针指向同一个数组的元素,则可以进行比较。指向前面的元素的指针变量“小于”指向后面元素的指针变量。
今日总结:今天把指针的复习完了,后面还有结构体,继续加油!