如:int i5
注:数组的下标是从0开始的,下标0对应数组第一个元素
int a[5] = {0};
//事实上,这个只是把第一个元素赋值为0,其余各位是自动初始化为0
int a[5] = {1};
//这里就是,第一个元素为1,其余元素为0int a[5] = {1, 2, 3, 4, 5};int a[5] = {1, 2, 3};
//前三位成功赋值,后两位,自动初始化为0int a[5] = {[2] = 2, [4] = [4]};
//数组a的第3位被赋值为2,第5位被赋值为4,因为数组的下标是从0开始的!!!(编译器会根据值的个数自动判断数组的长度)
int a[] = {1, 2, 3, 4, 5}如:
a0; // 访问a数组中第一行第一列的元素
b2; // 访问b数组中第三行第四列的元素
int a[2][3] = {1, 2, 3, 4, 5, 6};那到底是怎么存放的呢,用程序打印一下,观察结果。
#include <stdio.h>
int main()
{
int a[2][3] = {1, 2, 3, 4, 5, 6};
int i, j;
for (i = 0;i < 2;i++)
{
for (j = 0;j < 3;j++)
{
printf("a[%d][%d] = %d\n", i, j, a[i][j]);
}
}
return 0;
}结果如下:
a[0][0] = 1
a[0][1] = 2
a[0][2] = 3
a[1][0] = 4
a[1][1] = 5
a[1][2] = 6通过结果,是不是很容易看出来了~
int a[2][3] = {{1, 2, 3}, { 4, 5, 6}};或者写成这种样式:
int a[][3] = {
{1, 2, 3},
{4, 5, 6}
};以上这两种形式的行数都可以省略不写
int a[2][3] = {0};int a[2][3] = {[0][0] = 1, [1][2] = 2}; - 格式:类型名 *指针变量名
char *pa; //定义一个指向字符型的指针变量
int *pb; // 定义一个指向整型的指针变量
取地址运算符和取值运算符
注意:
值得一提的是 * 这个符号,在定义指针需要它,而在同时又是取值运算符。需要慢慢理解
==避免使用未初始化的指针==
int *p //例如这样就是未初始化的指针
-----------------------------
int *p = &a //例如这样就是初始化过的指针# include <stdio.h>
int main(){
char a = 'H';
int b = 521;
char *pa = &a;
int *pb = &b; // 这里的*是用来定义指针变量
printf("a=%c\n", *pa); // 这里打印的是地址指向的那个变量值
printf("b=%d\n", *pb); // 这里的*是用来取值
printf("sizeof pa = %d\n", sizeof(pa));
printf("sizeof pb = %d\n", sizeof(pb));
printf("a的地址:%p\n", pa); // 这里打印的是指针存放的地址
printf("b的地址:%p\n", pb);
return 0;
}结果:
a=H
b=521
sizeof pa = 8
sizeof pb = 8
a的地址:000000000062FE0F
b的地址:000000000062FE08==数组名其实是数组的第一个元素的地址==
# include <stdio.h>
int main(){
char str[3];
printf("请输入最帅的博主:");
scanf("%s", str);
printf("最帅博主的地址是:%p\n", str); // 查看数组名的地址
printf("最帅博主的地址是:%p\n", &str[0]); // 取数组第一个元素的地址
return 0;
}运行结果:
请输入最帅的博主:远方的星
最帅博主的地址是:000000000062FE10
最帅博主的地址是:000000000062FE10那数组其它位置的地址与首地址是什么关系呢?
# include <stdio.h>
int main(){
char a[] = "Hello";
int b[] = {1, 2, 3, 4, 5};
float c [] = {1.1, 2.2, 3.3, 4.4};
double d[] = {1.1, 2.2, 3.3, 4.4};
printf("a[0] -> %p, a[1] -> %p, a[2] -> %p\n", &a[0], &a[1], &a[2]);
printf("b[0] -> %p, b[1] -> %p, b[2] -> %p\n", &b[0], &b[1], &b[2]);
printf("c[0] -> %p, c[1] -> %p, c[2] -> %p\n", &c[0], &c[1], &c[2]);
printf("d[0] -> %p, d[1] -> %p, d[2] -> %p\n", &d[0], &d[1], &d[2]);
return 0;
}运行结果:
a[0] -> 000000000062FE10, a[1] -> 000000000062FE11, a[2] -> 000000000062FE12
b[0] -> 000000000062FDF0, b[1] -> 000000000062FDF4, b[2] -> 000000000062FDF8
c[0] -> 000000000062FDE0, c[1] -> 000000000062FDE4, c[2] -> 000000000062FDE8
d[0] -> 000000000062FDC0, d[1] -> 000000000062FDC8, d[2] -> 000000000062FDD0这里是十六进制,数组a,char类型,依次增加1个字节;数组b,int类型,依次增加4个字节;数组c,float类型,依次增加4个字节;数组d,double类型,依次增加8个字节。与下表相对,不难发现其规律,依次增加的大小为数据类型占的字节数。
char | 1个字节 |
|---|---|
char* | 8个字节 |
short int | 2个字节 |
int | 4个字节 |
unsigned int | 4个字节 |
float | 4个字节 |
double | 8个字节 |
long | 8个字节 |
long long | 8个字节 |
unsigned long | 8个字节 |
当指针指向数组元素的时候,我们可以对指针变量进行加减运算,这样做的意义相当于指向距离指针所在位置向前或向后第n个元素。
# include <stdio.h>
int main(){
char a[] = "Hello";
char *p = a;
printf("*p = %c, *(p+1) = %c, *(p+3) = %c\n", *p, *(p+1), *(p+3));
return 0;
}结果:
*p = H, *(p+1) = e, *(p+3) = l由此可见,加减代表的是方向。p+1指的是,指向数组的下一个元素,那么p-1,便是指向数组的上一个元素。
lvalue(左值):C语言中指用于识别或定位一个存储位置的标识符,左值必须是可改变的。
int *p[5]在指向字符指针的时候非常好用。
# include <stdio.h>
int main(){
char *p[] = {
"选择了就不必害怕",
"努力了就一定成功",
"加油,陌生人!"
};
int i;
for (i = 0;i < 3;i++){
printf("%s\n", p[i]); // 这里是不能写成*p[i]的,这样的意思是指向数组的第一个元素地址
}
return 0;
}int (*p)[5]例:这里使用数组指针完成的
# include <stdio.h>
int main(){
int temp[5] = {1, 2, 3, 4, 5};
int (*p2)[5] = &temp; //指向数组的指针
int i;
for (i = 0;i < 5;i++)
{
printf("%d\n", *(*p2 + i));
}
return 0;
}运行结果:
1
2
3
4
5arry指向的是包含5个元素的数组的指针
把一个地址的值取出来,称之为 ==“解引用”==
解引用到底是什么,查了一些资料,是否真的是 “取指针指向的地址的内容” 还不得而知,还需要日后慢慢的沉淀。
解引用:
*(array+i) == array[i]
*(*(array+i)+j) == array[i][j]
*(*(*(array+i)+j)+k) == array[i][j][k]下标索引的形式都可以转换为使用指针间接索引的形式。
# include <stdio.h>
int main(){
int array[4][5] = {0};
int i,j,k = 0;
for (i=0;i<4;i++)
{
for(j=0;j<5;j++)
{
array[i][j] = k++;
}
}
printf("*(array+1):%p\n", *(array + 1));//array+1的和进行解引用
printf("array[1]:%p\n", array[1]);//array第二行首地址
printf("&array[1][0]:%p\n", &array[1][0]);//对 array[1][0]取地址
printf("**(array+1):%d\n", **(array+1));//对array+1的和的解引用进行解引用
printf("array[1][0]:%d\n", array[1][0]);//array[1][0]的值
return 0;
}运行结果:
*(array+1):000000000062FDC4
array[1]:000000000062FDC4
&array[1][0]:000000000062FDC4
**(array+1):5
array[1][0]:5# include <stdio.h>
int main(){
int num = 521;
int *p1 = #
char *p2 = "天道酬勤";
void *p3;
p3 = p1;
printf("p1:%p, p3:%p\n", p1, p3);
p3 = p2;
printf("p2:%p, p3:%p\n", p2, p3);
return 0;
}结果如下:
p1:000000000062FE04, p3:000000000062FE04
p2:0000000000404000, p3:0000000000404000得到的结果是一样的,由此可见,是可以将任意数据类型的指针赋值给void的指针。
==但如果要根据void指针,取出其内容,最好进行数据类型的强制转换。==
# include <stdio.h>
int main(){
int num = 521;
int *p1 = #
char *p2 = "天道酬勤";
void *p3;
p3 = p1;
printf("p3:%d\n", *(int *)p3);//(int *)p3是进行类型强制转换,再加一个*,进行解引用,才能取出值
p3 = p2;
printf("p3:%s\n", (char *)p3);//由于字符串的特殊性,就不需要进行进引用了
return 0;
}结果如下:
p3:521
p3:天道酬勤NULL指针又称空指针,它有啥作用呢?
①避免重复分配内存
②只需要进行一处修改
之前见过用宏定义来定义常量,其实还可以利用const关键字。
例:
# include <stdio.h>
int main(){
const float pi = 3.14;
printf("%f\n",pi);
pi = 3.1415;
return 0;
}编译之后,会直接报错!
[Error] assignment of read-only variable 'pi'
// [错误]只读变量'pi'的赋值由此可以得到关于指向常量的指针的小结论:
指向常量的指针
①、指向非常量的常量指针
例如:
# include <stdio.h>
int main(){
int num = 521;
const int cnum = 1024;
int * const p = #
*p = 7758;//对指针指向的值进行修改
printf("*p:%d\n", *p);
return 0;
}输出为:
*p:7758将上述例子加以修改:
# include <stdio.h>
int main(){
int num = 521;
const int cnum = 1024;
int * const p = #
p = &cnum;//对指针本身进行修改
printf("*p:%d\n", *p);
return 0;
}编译结果,系统会报错!
[Error] assignment of read-only variable 'p'②、指向常量的常量指针
(和上例类似)
指针真的是C的灵魂所在,欲速则不达,花的时间也比较长,不断练习才能更好地理解。
这一阶段的笔记就先记录到这里,但学C的道路仍然还很漫长。。。
路漫漫其修远兮,吾将上下而求索。
大家一起加油吧!

作者:远方的星 CSDN:https://blog.csdn.net/qq_44921056
本文仅用于交流学习,未经作者允许,禁止转载,更勿做其他用途,违者必究。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。