百度
360搜索
搜狗搜索

常量指针数组,c语言中的数组名字是指针常量还是常量指针呢详细介绍

本文目录一览: 指针与数组的关系是什么啊

1、指针:系统为某一个变量开辟单元格,指针便指向此单元格的变量值。
2、数组:系统为某一组数开辟一组单元格,数组首地址便是你定义的数组变量名。
数组和指针的唯一区别是,不能改变数组名称指向的地址。
对于数组来说,数组的首地址,也可以用指针来表示操作,如:
int a[10];
int *p,n;
p = a;
对第一个元素取值,可以用几种方法:
n =a[0];
n = *p;
n = p[0];
n = *(p+0) ;
但是以下语句则是非法的:
readings = totals; // 非法!不能改变 readings totals = dptr; // 非法!不能改变 totals
数组名称是指针常量。不能让它们指向除了它们所代表的数组之外的任何东西。
扩展资料
下面的程序定义了一个 double 数组和一个 double 指针,该指针分配了数组的起始地址。随后,不仅指针符号可以与数组名称一起使用,而且下标符号也可以与指针一起使用。
int main()
{
const int NUM_COINS = 5;
double coins[NUM_COINS] = {0.05, 0.1, 0.25, 0.5, 1.0};
double *doublePtr; // Pointer to a double
// Assign the address of the coins array to doublePtr
doublePtr = coins;
// Display the contents of the coins array
// Use subscripts with the pointer!
cout << setprecision (2);
cout << "Here are the values in the coins array:\n";
for (int count = 0; count < NUM_COINS; count++)
cout << doublePtr [count] << " ";
// Display the contents of the coins array again, but this time use pointer notation with the array name!
cout << "\nAnd here they are again:\n";
for (int count = 0; count < NUM_COINS; count++)
cout << *(coins + count) << " ";
cout << endl;
return 0;
}
程序输出结果:
Here are the values in the coins array: 0.05 0.1 0.25 0.5 1 And here they are again: 0.05 0.1 0.25 0.5 1
当一个数组的地址分配给一个指针时,就不需要地址运算符了。由于数组的名称已经是一个地址,所以使用 & 运算符是不正确的。但是,可以使用地址运算符来获取数组中单个元素的地址。

C语言:简述一下“数组和指针的关系”?

数组是一类同类型变量的集合,类似于属于上的集合的概念,数字也是有集合的,比如整数集,实数集等。
数组也是一个集合,数组的名字是集合的名字,数组后面的方括号里的数字,表示这个集合的大小,数组名前面的类型说明符,表示这个数组是什么类型的集合,比如:
int a[5], a是数组的名字,因为我们后面要用到数组,所以我们必须要取一个名字,要不然程序也不知道,你调用的数组是哪个不是?[5]方括号里的数字5,表示这个数组的大小是五个数的集合,数组名最前面的int是类型说明符,说明数组这个集合里的数是什么类型的,在C语言里,基本类型就那么几个,我们除了用基本类型外,还可以使用我们自己设置的结构体等类型,相当于数学里面,集合的说明,用来说明这个集合什么实数集合,还是整数集合的类似意义。
指针,我们直接可以用地址来代替指针这个名字,指针就是地址,你把任何变量看成一个人,每个人肯定都有自己住的地方,变量也一样,变量在内存上,一定也有地址,而指针就是地址。C语言里可以有两种调用变量的形式,一种直接使用变量的名字来调用,比如 int a=10;
意思就是把10这个数给变量a,除了这样用以为,还能通过指针来使用,指针是地址,需要用到取地址符&,比如 int *c, a; c=&a;像上面的语句,c是一个指针,怎么识别c是指针呢?因为c在声明的时候使用了指针声明符*,用来说明c是一个指针,而a则是一个变量,因为没有使用指针声明符进行声明,c=&a,这个语句即把a的地址,给了c,因为c是指针,所以c需要的是变量的地址,而不是变量的名字,这个时候在赋值号=的后面使用了取地址符&,用来取出变量a的地址给C,当我们要用a的时候,我们可以通过指针c来访问变量a,通过c上的地址,来找到a所在的位置,再取出a的值,这里需要使用解地址符 *,假设有个变量d需要变量a一样的值,我们需要使用d=(*c);这语句表示通过c的地址,访问a,取出a的值赋值给变量d,这里也有一个*符号,但是这个符号不是指针声明符了,而是解地址符了,那么怎么判断两种用途的*符号的作用呢?很简单,指针声明符值在变量声明,或者指针声明的时候使用,其他地址都不是指针声明符号,而是解地址符,怎么判断一个语句是声明还是其他语句呢?很简单,不管是什么声明,前面都需要类型说明符,比如 int a,*c。这是一个声明,声明一个变量a,类型是int型,一个指针c,存放地址,存放的是一个int型变量的地址。对,你没看错,指针也需要类型说明符,因为C语言里,有好多类型,他们大小不一样,需要说明,然后使用他们的过程,编译器会帮你解决的,你不用关心实现的问题。
好,上面大致说明了,数组是什么,指针是什么?那么数组和指针的关系是什么呢?乍一看,貌似没有任何关系,对吧,但是还是有的,因为数组也是放在内存上的啊,显然数组也是有地址的,即有指针的对吧,所以我们应该可以使用数组的指针对吧,int a[5]这是一个数组对吧,那么它的指针要怎么设定呢?答案是这样的, int [] *c,这是什么意思呢?很简单,c前面有指针说明符吧,说明c是一个指针,那么c这个指针是面向什么变量呢?是面向int [],那么int []是什么?[]是数组的特征,[]的前面有个int,说明c这个指针应该是指向一个int型的数组的对吧,所以这是一个指向数组的指针对吧,但是问题来了,数组是一个集合啊,比如上面说的int a[5],
这个数组是由五个int型的数组成的集合,你这个指针是指向哪一个数啊?如果你指向一个数,而指向一个整体,我怎么用?我们最常用的需求是,能访问数组里的每一个数啊对吧。这里有了需求,我们就有一个约定俗成的规定,那就是什么规定呢?数组的名字给它一个另外的功能,什么功能呢?就是数组的名字本身就是一个指针,那么要确定是哪个数的呢?我们默认是数组最开头的指针,即a[5]中的数组名字a是一个指针,代表a[0]的地址,这是一个默认,因为我们有需求,为了能快速简便的通过指针来使用数组里的数,而不是使用数组整个地址,因为没有意义,通过这个设定之后,我们有了进一步的需求,那么我们a[1]的元素怎么办?我们也想通过指针来使用啊,很简单,直接使用++或+即可,a+1,数组名a代表a[0]的地址,那么我们a+1就用来表示a[1]的地址,一点都不过分,虽然看起来有点变扭,但是符合我们的需求,而且简便快速,同理也可以使用++,--的用法,但是地址的* ,/就没有意义了,所以指针的 *, /是不能使用的,了解了约定俗成的这个规定后,百分99的程序都可以看懂了,希望能理解我说的,如果不理解,多看几遍我说的吧,然后对照着使用数组和指针的程序理解一下,用多了,看多了,自然就懂了。
指针就是指针,数组就是数组;在建立关系之前,指针与数组毫无关系。
一旦一个与某数组元素类型兼容的指针指向了这个数组的某个元素,这个指针就与这个数组建立了关系,之后就可以用指针来完成对这个数组的全部操作,其作用类似于数组名且比数组名更具灵活性。
由于指针是变量,数组名是常量,所以与数组建立了关系的指针可以用前++和后++操作指针,有不少操作要比直接用数组名来得方便且据说时效要高。
以上全是个人理解与使用感受,供参考。
一、概念
数组:数组是用于储存多个相同类型数据的集合。
指针:指针相当于一个变量,但是它和不同变量不一样,它存放的是其它变量在内存中的地址。
二、赋值、存储方式、求sizeof、初始化等
1.赋值
同类型指针变量可以相互赋值,数组不行,只能一个一个元素的赋值或拷贝
2.存储方式
数组:数组在内存中是连续存放的,开辟一块连续的内存空间。数组是根据数组的下进行访问的,多维数组在内存中是按照一维数组存储的,只是在逻辑上是多维的。
数组的存储空间,不是在静态区就是在栈上。
指针:指针很灵活,它可以指向任意类型的数据。指针的类型说明了它所指向地址空间的内存。
指针:由于指针本身就是一个变量,再加上它所存放的也是变量,所以指针的存储空间不能确定。
3.求sizeof
数组:
数组所占存储空间的内存:sizeof(数组名)数组的大小:sizeof(数组名)/sizeof(数据类型)
指针:
在32位平台下,无论指针的类型是什么,sizeof(指针名)都是4,在64位平台下,无论指针的类型是什么,sizeof(指针名)都是8。
关于指针和数组求sizeof,我在之前的博客中写过,现将连接贴上:https://blog.csdn.net/cherrydreamsover/article/details/81589838
4.初始化
数组:
(1)char a[]={"Hello"};//按字符串初始化,大小为6.(2)char b[]={'H','e','l','l'};//按字符初始化(错误,输出时将会乱码,没有结束符)(3)char c[]={'H','e','l','l','o','\0'};//按字符初始化1234这里补充一个大家的误区,就是关于数组的创建和销毁,尤其是多维数组的创建与销毁。(1)一维数组:int* arr = new int[n];//创建一维数组delete[] arr;//销毁(2)二维数组:int** arr = new int*[row];//这样相当于创建了数组有多少行for(int i=0;i
<row;i++){arr[i] = new int[col]; 到这里才算创建好了} 释放for(int i="0;i<row;i++){delete[]" arr[i];}delete[] arr;
指针:

//(1)指向对象的指针:(()里面的值是初始化值)int *p=new int(0) ; delete p;//(2)指向数组的指针:(n表示数组的大小,值不必再编译时确定,可以在运行时确定)int *p=new int[n]; delete[] p;//(3)指向类的指针:(若构造函数有参数,则new Class后面有参数,否则调用默认构造函数,delete调用析构函数)Class *p=new Class; delete p;//(4)指针的指针:(二级指针)int **pp=new (int*)[1];pp[0]=new int[6];delete[] pp[0];12345678910这里我们区分两个重要的概念:指针数组、数组指针。

(1)指针数组:它实际上是一个数组,数组的每个元素存放的是一个指针类型的元素。

int* arr[8];//优先级问题:[]的优先级比*高//说明arr是一个数组,而int*是数组里面的内容//这句话的意思就是:arr是一个含有8和int*的数组1234

请点击输入图片描述

(2)数组指针:它实际上是一个指针,该指针指向一个数组。

int (*arr)[8];//由于[]的优先级比*高,因此在写数组指针的时候必须将*arr用括号括起来//arr先和*结合,说明p是一个指针变量//这句话的意思就是:指针arr指向一个大小为8个整型的数组。1234

请点击输入图片描述

三、传参

数组:

数组传参时,会退化为指针,所以我们先来看看什么是退化!(1)退化的意义:C语言只会以值拷贝的方式传递参数,参数传递时,如果只拷贝整个数组,效率会大大降低,并且在参数位于栈上,太大的数组拷贝将会导致栈溢出。(2)因此,C语言将数组的传参进行了退化。将整个数组拷贝一份传入函数时,将数组名看做常量指针,传数组首元素的地址。

1.一维数组的传参

#include

阅读更多 >>>  c语言数组求最大值和最小值,c语言求数组中最大值和最小值及其下标

//传参方式正确//用数组的形式传递参数,不需要指定参数的大小,因为在一维数组传参时,形参不会真实的创建数组,传的只是数组首元素的地址。(如果是变量的值传递,那么形参就是实参的一份拷贝)void test(int arr[]){}//传参方式正确//不传参数可以,传递参数当然也可以void test(int arr[10]){}//传参方式正确//一维数组传参退化,用指针进行接收,传的是数组首元素的地址void test(int *arr){}//传参方式正确//*arr[20]是指针数组,传过去的是数组名void test2(int *arr[20]){}//传参方式正确//传过去是指针数组的数组名,代表首元素地址,首元素是个指针向数组的指针,再取地址,就表示二级指针,用二级指针接收void test2(int **arr){}int main(){int arr[10] = {0};int *arr2[20] = {0};test(arr);test2(arr2);}2.二维数组的传参

//传参正确//表明二维数组的大小,三行五列void test(int arr[3][5]){}//传参不正确//二维数组的两个方括号,不能全部为空,也不能第二个为空,只能第一个为空void test(int arr[][]){}//传参正确//可以写成如下这样传参形式,但是不能写int arr[3][]void test(int arr[][5]){}//传参不正确//arr是一级指针,可以传给二维数组,但是不能正确读取void test(int *arr){}//传参不正确//这里的形参是指针数组,是一维的,可以传参,但是读取的数据不正确void test(int* arr[5]){}//传参正确//传过去的是二维数组的数组名,即数组首元素的地址,也就是第一行的地址,第一行也是个数组,用一个数组指针接收void test(int (*arr)[5]){}//传参不正确//可以传参,但是在读取的时候会有级别不同的问题void test(int **arr){}int main(){int arr[3][5] = {0};test(arr);}指针:

1.一级指针传参

当函数参数部分是一级指针时,可以接受什么参数例如:test(int*p)

(1)可以是一个整形指针(2)可以是整型变量地址(3)可以是一维整型数组数组名

#include

void print(int *p, int sz){int i = 0;for(i=0; i
<sz; i++){printf("%d\n", *(p+i));}}int main(){int arr[10]="{1,2,3,4,5,6,7,8,9};int" *p="arr;int" sz="sizeof(arr)/sizeof(arr[0]);//一级指针p,传给函数print(p," sz);return 0;}2.二级指针传参
即当函数参数部分是二级指针时,可以接受什么参数例如:test(int**p)

(1)二级指针变量(2)一级指针变量地址(3)一维指针数组的数组名

#include

void test(int** ptr){printf("num = %d\n", **ptr);}int main(){int num = 10;int*p = #int **pp = &p;test(pp);test(&p);return 0;}四、函数指针、函数指针数组、函数指针数组的指针

1.函数指针

void test(){printf("hehe\n");}//pfun能存放test函数的地址void (*pfun)();函数指针的形式:类型(*)( ),例如:int (*p)( ).它可以存放函数的地址,在平时的应用中也很常见。

2.函数指针数组

形式:例如int (*p[10])( );因为p先和[ ]结合,说明p是数组,数组的内容是一个int (*)( )类型的指针函数指针数组在转换表中应用广泛

3.函数指针数组的指针

指向函数指针数组的一个指针,也就是说,指针指向一个数组,数组的元素都是函数指针

void test(const char* str){printf("%s\n", str);}int main(){//函数指针pfunvoid (*pfun)(const char*) = test;//函数指针的数组pfunArrvoid (*pfunArr[5])(const char* str);pfunArr[0] = test;//指向函数指针数组pfunArr的指针ppfunArrvoid (*(*ppfunArr)[10])(const char*) = &pfunArr;return 0;}

一维 数组名 为指针常量 的原因

这也不是什么规定.这与数组的存储方式有关,你知道,数组在定义后,只要程序运行了,系统就会为它分配一个连续的存储单元,每个存储单元都是有确定的地址的.而数组名就对应着那个连续的存储单元的首地址,即第一个元素的地址,它就代表这个地址,这是个定值,也就是常量.因为指针的内容都是地址,数组名的内容也是地址,所以,才有数组名是指针常量这一说.这个词实际就是说数组名就是一个地址常量.既是常量,怎么能对它赋值呢?2就是2,你可以对它再进行赋值动作吗?不知我这样说,你是否能明白.就这样,朋友.

数组为什么是指针常量?

  数组名绝对不等于指针,而且不是指针。
  数组名是指针常量,地址是绝对的,score指向受保护,但首地址的内容可以改变,所以数组首地址应该是指针常量int *const score。
  指针是一个变量,变量的值是另外一个变量的地址。那么,既然指针是变量,那么指针必然有自己的存储空间,只不过是该存储空间内的值是一个地址值,而不是别的内容。
1、类型不匹配 "张三"是个字符串数组,
而xingming[50]只是数组中一个元素,
是char类型的、
这是数组初始化问题,任何数组都不允许这样初始化
2、数组在定义后,系统就会为其分配一个连续的存储空间,
而数组名对应这段连续存储单元的首地址,即第一个元素的地址,
这是个定值,是不能改变的,是个常量.
如果是个变量,那么变量是可以赋值的,比如int b = 1;
但是数组名是个常量,比如char xingming[50];的首元地址是100,
那么xingming就是500这个值,500 = 1,这样行吗,显然是不可以的,
即数组名不能赋值
所以数组名是个指针常量
数组只能在定义的时候赋值,拷贝内存必须用到memcpy
memcpy(xingming, "张三");
这个跟指针常量没有关系,但数组可以看成是指针常量,因为指针可以++、--,但数组不行
举个例子:
int a[100];
a++; // 错误,数组不能+=
int* p = a;
p++; // 可以,因为p是个变量
const int* q = a;
q++; // 错误,因为q是个常量指针,指向的地址不可变
char xingming[50]="张三"; //这样是对的

char xingming[50];
xingming[50]="张三";
这样是错的!
xingming[50]表示第51个数组元素(字符型),因此不能这样赋值
①char xingming[50]="张三"; //这样可以;
②char xingming[50]; xingming[50]="张三"; //这样就不行了
原因如下:
①的意思相当于:定义一个大小为50的字符数组,第一个字符(xingming[0])值为‘张’,第二个字符(xingming[1])的值为‘三’,其余字符(xingming[2]至xingming[49])值为空;
②有两个错误:(1)数组越界:数组xingming有50个元素,但下标是从0开始至49的,没有到50;
(2)xingming[50]在这里不是定义,所以表示下标50的元素(一个元素,即一个字符),而后面给的值确是一个字符串;
说明:
数组定义时,后面的等于相当于给每个元素分别赋值,如果值不够,后面的元素值就为0(或者空),而除定义之外,任何地方,数组名加下标都表示一个元素;另外补充一点:数组定义时如果,要求给定的元素个数等于定义的元素个数,中括号里面的数值可以不要,如:
int a[]={1,2,3,4}; //这句话相当于定义了一个大小为4的int型数组,各个元素的值分别为1,2,3,4;
a[3]=5; //这句话相当于将第4个元素的值改为5;

C语言中指针和数组是怎样相互转换的

数组名可以认为是常量指针, 本身值不能更改 ,但是可以参与运算。
指针可以当做数组使用, 按照下标方式访问。
以上仅限于一维指针和一维数组
对于多维数组, 可以转为一维指针。
指针数组,就是一个数组里存放的都是指针,比如*p[8];p[0]里存放的就是一个指针数据
数组指针,数组名就是一个指向数组起始地址的指针,数组下标是萦引,比如num[0],他就相当于num+0;
num这个指针没移动,于是取的是数组的第一个。num[1]相当于数组指针移1,于是指向数组第二个

二维数组与指针、指针数组、数组指针的用法

二维数组和指针⑴ 用指针表示二维数组元素。 要用指针处理二维数组,首先要解决从存储的角度对二维数组的认识问题。我们知道,一个二维数组在计算机中存储时,是按照先行后列的顺序依次存储的,当把每一行看作一个整体,即视为一个大的数组元素时,这个存储的二维数组也就变成了一个一维数组了。而每个大数组元素对应二维数组的一行,我们就称之为行数组元素,显然每个行数组元素都是一个一维数组
下面我们讨论指针和二维数组元素的对应关系,清楚了二者之间的关系,就能用指针处理二维数组了。 设p是指向二维数组a[m][n]的指针变量,则有:
int* p=a[0];//此时P是指向一维数组的指针。P++后,p指向 a[0][1]。
如果定义int (*p1)[n];p1=a;p1++后,p1指向a[1][0];
则p+j将指向a[0]数组中的元素a[0][j]。 由于a[0]、a[1]┅a[M-1]等各个行数组依次连续存储,则对于a数组中的任一元素a[i][j],指针的一般形式如下: p+i N+j 相应的如果用p1来表示,则为 (p1+i)+j 元素a[i][j]相应的指针表示为: ( p+i N+j) 相应的如果用p1来表示,则为 ( (p1+i)+j) 同样,a[i][j]也可使用指针下标法表示,如下: p[i N+j] 例如,有如下定义: int a[3][4]={{10,20,30,40,},{50,60,70,80},{90,91,92,93}}; 则数组a有3个元素,分别为a[0]、a[1]、a[2]。而每个元素都是一个一维数组,各包含4个元素,如a[1]的4个元素是a[1][0]、a[1][1]、a[1]2]、a[1][3]。 若有: int p=a[0]; 则数组a的元素a[1][2]对应的指针为:p+1 4+2 元素a[1][2]也就可以表示为:( p+1 4+2) 用下标表示法,a[1][2]表示为:p[1 4+2] 特别说明: 对上述二维数组a,虽然a[0]、a都是数组首地址,但二者指向的对象不同,a[0]是一维数组的名字,它指向的是a[0]数组的首元素,对其进行“ ”运算,得到的是一个数组元素值,即a[0]数组首元素值,因此, a[0]与a[0][0]是同一个值;而a是一个二维数组的名字,它指向的是它所属元素的首元素,它的每一个元素都是一个行数组,因此,它的指针移动单位是“行”,所以a+i指向的是第i个行数组,即指向a[i]。对a进行“ ”运算,得到的是一维数组a[0]的首地址,即 a与a[0]是同一个值。当用int p;定义指针p时,p的指向是一个int型数据,而不是一个地址,因此,用a[0]对p赋值是正确的,而用a对p赋值是错误的。这一点请读者务必注意。 ⑵ 用二维数组名作地址表示数组元素。 另外,由上述说明,我们还可以得到二维数组元素的一种表示方法: 对于二维数组a,其a[0]数组由a指向,a[1]数组则由a+1指向,a[2]数组由a+2指向,以此类推。因此, a与a[0]等价、 (a+1)与a[1]等价、 (a+2)与a[2]等价,┅,即对于a[i]数组,由*(a+i)指向。由此,对于数组元素a[i][j],用数组名a的表示形式为: ( (a+i)+j) 指向该元素的指针为: *(a+i)+j 数组名虽然是数组的地址,但它和指向数组的指针变量不完全相同。
第一,指针变量的值可以改变,即它可以随时指向不同的数组或同类型变量,而数组名自它定义时起就确定下来,不能通过赋值的方式使该数组名指向另外一个数组。
第二,数组名是指针,类型是指向元素类型的指针,但值是指针常量,声明数组时编译器会为声明所指定的元素数量保留内存空间。数组指针是指向数组的指针,声明指针变量时编译器只为指针本身保留内存空间。
例4 求二维数组元素的最大值。
该问题只需对数组元素遍历,即可求解。因此,可以通过顺序移动数组指针的方法实现。 main() { int a[3][4]={{3,17,8,11},{66,7,8,19},{12,88,7,16}}; int p,max; for(p=a[0],max= p;p

max) max= p; printf("MAX=%d/n",max); } 执行结果: MAX=88 这个程序的主要算法都是在for语句中实现的:p是一个int型指针变量;p=a[0]是置数组的首元素地址为指针初值;max= p将数组的首元素值a[0][0]作为最大值初值;p
<a[0]+12是将指针的变化范围限制在12个元素的位置内;p++使得每比较一个元素后,指针后移一个元素位置。 例5 求二维数组元素的最大值,并确定最大值元素所在的行和列。 本例较之上例有更进一步的要求,需要在比较的过程中,把较大值元素的位置记录下来,显然仅用上述指针移动方法是不行的,需要使用能提供行列数据的指针表示方法。 main() { int a[3][4]="{{3,17,8,11},{66,7,8,19},{12,88,7,16}};" p="a[0],max,i,j,row,col;" max="a[0][0];" row="col=0;" for(i="0;i<3;i++)" for(j="0;j
max) { max= (p+i 4+j); row=i; col=j; } printf("a[%d][%d]=%d/n",row,col,max); } 程序运行结果: a[2][1]=88 ⑶ 行数组指针 在上面的说明中我们已经知道,二维数组名是指向行的,它不能对如下说明的指针变量p直接赋值: int a[3][4]={{10,11,12,13},{20,21,22,23},{30,31,32,33}}, p; 其原因就是p与a的对象性质不同,或者说二者不是同一级指针。C语言可以通过定义行数组指针的方法,使得一个指针变量与二维数组名具有相同的性质。行数组指针的定义方法如下: 数据类型 ( 指针变量名)[二维数组列数]; 例如,对上述a数组,行数组指针定义如下: int ( p)[4]; 它表示,数组 p有4个int型元素,分别为( p)[0]、( p)[1]、( p)[2]、( p)[3] ,亦即p指向的是有4个int型元素的一维数组,即p为行指针

此时,可用如下方式对指针p赋值:

p=a;

(4)指针数组的定义

指针数组是指每个元素中存放的是指针。定义为 int *p[4];sizeof(p)=16,返回的是数组的总空间

阅读更多 >>>  excel什么时候用数组公式,excel 什么时候使用“数组公式”啊

指针与数组

数组名所代表的就是该数组最开始的一个元素的地址,在计算数组元素a[i]的值时,C语言实际上线将其转换为 (a+i)的形式,然后再进行求值。他们是等价的,可以将指针后面加下标,比如pa[i]和 (pa+i)是等价的,但是指针比单纯的数组名要快一些。 有一点很重要的,数组名和指针之间有一个不同之处,指针是一个变量,因此,pa+a和pa++都his合法的,但数组名不是变量(类似一个宏定义?用数组名替换地址?),所以进行对自身的增减运算是非法的。 有时如果将数组名传递给函数,函数可以根据情况判定是按照数组处理还是按照指针处理,随后根据相应的方式操作该函数,为了更直观的表示数组名和指针,可以同时使用两种表示方法。 也可以将数组的一部分传递给函数,不必须从起始位置运算、对于函数来说,它并不关心所引用的是否是一个大数组的其中一部分。
地址算数运算 *allocp = allocbuf起始是存储空间的起始位置。 之后的函数中allocbuf + ALLOCSIZE是存储空间的最后的地址,因为存储空间不一定是从0开始,所以起始地址加上总大小得到的就是这个存储空间最后的地址。减去allocp是将已分配的空间减去,得到的必然是小于或等于空间大小的数,这个数就是剩余的空间的大小。 这就比如从30000开始之后10000的部分是存储空间,已分配空间在35000那么30000加10000减去35000就是剩余的空间了。 之后的那个allocp自增让我懵了一下。自增之后为啥又减了,仔细看发现。allocp += n确实是自增了,本身的地址也改变了。但是allocp - n只是将数值传回了,并没有对自己赋值。 这个函数确实不完善,afree函数很简单就是确定参数的地址是否在存储空间内。是的话就将已分配的地址变成新的地址。 指针也可以初始化,对指针有意义的初始化只能是0或者是表示地址的表达式,表达式代表的地址必须是已经定义的具有适当类型的数据的地址。 static char *allocp = allocbuf; allocbuf需要在之前已经定义为字符数组才是有意义的。 C语言保证0永远不是有效的数据地址。因此,返回值0可用来表示发生了异常事件。 指针与整数之间不能相互转换,但0是唯一的例外,常熟0可以赋值给指针,指针也可以和常量0进行比较。程序中通常用符号常量NULL代替常量0。符号常量0定义在标准头文件

中。 在某些情况下对指针可以进行比较运算。如果指针p和q是同一个数组的成员,那么他们之间就可以进行类似于==、!=、<,>=的关系比较运算。任何指针与0进行相等或不等的比较运算都有意义。但是指向不同数组的元素的指针之间的算数或比较运算没有定义,(这里有一个特例。指针的算数运算中可使用数组最后一个元素的下一个元素的地址。) 指针可以和整数进行相加或相减运算。无论指针对象是何种类型都成立,相加的整数会根据指针指向的类型长度按比例缩放, 指针相减也是有意义的,同数组中的指针相减会得到指针之间字符的数量。 指针的算数运算具有一致性,所有的指针运算都会自动考虑它所指向的对象的长度。 有效的指针运算包括相同类型指针之间的赋值运算;指针同整数之间的加法或减法运算;指向相同数组中元素的两个指针间的减法或比较运算;将指针赋值为0或指针与0之间的比较运算。除此之外其他所有的指针运算都是非法的。(两个指针之一是void *类型的情况除外)

C语言中数组和指针的问题。

前面的都没什么问题,就是最后“a的值与a[0]相同,知识a包含a[o],a[1],a[2]。而a[0]包含a[0][0] a[0][1] a[0][2] a[0][3]"是错的,这句根本就不成立。
2.A[0]是一个2级常指针,指向一个大小为4的一维数组结构。问题是:中3)所以,int A[2][3][4]={0}; A是一个三维数组,其中A[0]和A[
你可以去看这篇文章,
http://book.51cto.com/art/201103/248068.htm
兴许能对你有所帮助。
你的理解是错误的,你可以再看一下其他的资料。
不怎么对。
首先,不要理会所谓“常指针”的说法。C语言中“常量”有特殊的含义——某些种类的字面量(如类型为int的整数常量);有时也指const限定符;但并不见得和字面上的“不可改变”的“常量”同义(例如const对象事实上是只读对象而不是真正意义上的常量,通过显式转换指针类型可以修改并引起不可预料的后果),滥用这个概念这只会使所要讨论的问题更容易被混淆。另外,建议LZ系统地复习至少这些基本概念:对象、左值、类型和值,如果看不懂以下内容的话。
数组是数组,指针是指针。a是a,a[0]是a[0]。只不过在作为sizeof、&的操作数等有限几个左值上下文之外的场合数组a会退化(隐式转换,结果的类型是元素的指针类型,丢弃了数组类型中的长度)成指向首个元素的指针&a[0],所以容易造成误解。
先考虑LZ最后的表述。
注意C语言中对象可以理解为被占据的连续的内存。值是对象的内容,包含类型和实际的存储表示(对整数类型就是数值,对指针类型一般实现为平坦地址空间元素的整数)。数组对象a的类型是int[3][4],即元素类型为int[4]、具有3个元素的数组类型;a[0]是它的元素,也是数组对象——类型是int[4]。显然类型不同,所以值不同。
a包含a[0],a[1],a[2]。而a[0]包含a[0][0] a[0][1] a[0][2] a[0][3]——正确。
再考虑:LZ之前的陈述。
对象的地址是运行期对象占据的连续内存的首个内存单元(字节)在地址空间的编号。“a,a[0]与a[0][0]是占用着3个不同地址的存储单元”是错的,因为根本就不能确定每个对象只占据一个地址单元。考虑一般实现的内存布局,a、a[0]、a[0][0]的指针&a、&a[0]、&a[0][0]具有不同的值(类型不同),但在存储的数值上相等。注意表达式&a不是左值,不指称一个具有存储的对象——事实上这个表达式的值在编译期即可确定。因此这些指针的值编译器当然知道,但不会在运行期被存储在以上对象内部。当然用一个指针变量在运行期保存这个值是可行的,例如p=&a[0];printf("%p",p);直接使用这个值printf("%p",&a[0]);同义。
a[0]是一个类型为int[4]的数组,是a的第一个元素,它的地址蕴涵于指针&a[0]中。注意&a[0]刚好能通过非左值上下文的作为表达式的a转换得到。 形如p=a;的用法,实际上就是p=&a[0];。

c语言中的数组名字是指针常量还是常量指针呢

score是一个常量指针,是int const *
const int *p是底层const 表示可以修改指针的地址,但不能修改指针所指向的对像的值,int const *p
是顶层const 表示不可以修改指针的地址,但可以修改指针所指向的对像的值。
数组名是指针常量,指针不是有常量指针和指针常量和常量常指针吗?地址是绝对的,score指向受保护,但首地址的内容可以改变,所以数组首地址应该是指针常量int *const score,你的第二个注释说地址就是指针,应该是指针常量,指针就是地址是一种宽泛的说法,不对请指正哈

定义了一个常数组,为什么能用指针改变数组元素的值?

是的,当指针指向数组的地址时,可以通过指针改变数组元素的值。
一个数组a[],a是数组的起始地址;
一个指针p=a,也就是让指针指向数组的起始地址;
这时*p等同于p[0],也就是等同于a[0]。
因此你的程序中,*p=5之后,a[0]和p[0]事实上都是同一个变量,都等于5。
另外,用const来说明一个变量不允许改变的时候,事实上const后面的变量还是变量,不是常量,在内存中是有开辟存储空间的,从本质上说是可以被重新赋值的,只不过编译器在编译的时候会检测,不让你在其他地方重新赋值,但当你的变量名更改之后,编译器是无法自动识别的,所以可以改变变量的值。
如果你还要问为什么,那只能告诉你,这是C的规则,记住就行。
这个问题稍微有些复杂。
通过const声明的常量变量,只是保证在写代码时不能通过变量名(本例是a)更改变量的值,但依然可以通过其他方式修改变量所在的内存上的值,比如通过指针。
另外常量变量有两种存放位置:如果定义在函数内部,它存放在函数的栈帧中(本例就是这种情况);如果定义在全局,它存放在进程内存的常量区。对于前者,通过指针修改不仅能通过编译,也能正常运行,并且真实地修改掉了常量变量所在内存上存储的值。对于后者,由于进程内存的常量区是只读不可写的,如果通过指针修改它的值,所以尽管能通过编译,但是会在运行时发生内存读写异常,操作系统报错。
因为
p=(int *)a;
这里你对p赋值时,做了强制类型转换。
这样在用p访问时,就认为是“非常数”的指针了。
这就相当于,用a访问的人具有一般权限(只读权限),但是给p开了一个特殊权限(写权限)。
最根本的原因是你做了强制类型转换:
void main()
{
const int a[3]={2,4,1};
int *p;
p=(int *)a;
*p=5;
((int*)a)[0]=6; // 虽然定义a是常量数组,但是做了强制类型转换之后,仍然可以写入。
printf("%d",a[0]);
printf("%d",p[0]);
}
常数组不可以改变值。
定义数组时,如果有const修饰,表示其为常数组。
对于常数组,会在编译后放置与常数区间中,这部分内容是只读的,不可以做任何修改。
一旦对其进行修改,就会导致程序崩溃。
所以常数组无论使用何种方法,均不能修改其值。
在C语言中,通过指针的强制转换,可以取消其常量标记。
比如
const int a[] = {1,2,3,4};
int* p = (int *)a;
这样的强制转换,可以去除掉a的常量属性,然后通过
*(p+i)=xxx;
这样的语句,改变a的第i个值。
但是即使是这样可以编译通过,运行时修改值后,也会引起程序崩溃,使修改没有意义。

网站数据信息

"常量指针数组,c语言中的数组名字是指针常量还是常量指针呢"浏览人数已经达到23次,如你需要查询该站的相关权重信息,可以点击进入"Chinaz数据" 查询。更多网站价值评估因素如:常量指针数组,c语言中的数组名字是指针常量还是常量指针呢的访问速度、搜索引擎收录以及索引量、用户体验等。 要评估一个站的价值,最主要还是需要根据您自身的需求,如网站IP、PV、跳出率等!