小小的C语言问题指针数组赋值关于指针和数组。(共8篇)由网友“whale”投稿提供,下面是小编为大家准备的小小的C语言问题指针数组赋值关于指针和数组。,欢迎阅读借鉴。
篇1:小小的C语言问题指针数组赋值关于指针和数组。
先上代码吧:
?
#include
#include
using namespace std ;
int replacefun(char* str, char c1, char c2);
int main(void)
{
char * p = “I love you China, do you love me?”; // 用指针的形式定义一个字符数组
int m = 0;
m = replacefun(p, 'o', 'c');
cout << m << endl;
return 0;
}
int replacefun(char* str, char c1, char c2)
{
int num = 0;
while (*str != '\0')
{
if (*str == c1)
{
*str = c2; // 这句话调试的时候内存报错
num++;
}
str++;
}
return num;
}
这个程序实现的目的的是替换指定的字符,在编译的时候没有任何错误,但是在运行的时候,程序意外终止,
小小的C语言问题指针数组赋值关于指针和数组,
电脑资料
《小小的C语言问题指针数组赋值关于指针和数组。》()。。
于是,启动利器,单步调试。。。跳进函数后,发现在*str到达'o'之前一切正常,不过。。到了'o'之后,结果说内存错误,无法赋值。
经过多方查找资料和询问,得知:
char *p=“abcde”;的时候,字符串是不可以修改的!
而char p[]=“abcde”;的时候,字符串是可以修改的!
同一个字符串,用指针定义的时候在常量区,而用数组定义的时候在栈中。
就是刚刚上面的那个
I love you China, do you love me?
是一个常量。
据大婶说:
“I love you China, do you love me?”
在存放在.rodata段,该段是只读的,当你强行做修改的时候,当然要报错喽。
而定义为数组的形式之后:就把这个字符串拷贝进数组了,对于数组中的内容,可以随便修改呀. 原来的字符串还是不变的。。。
以上总结,涨姿势了。
继续C++。
篇2:十六、数组和指针
指针和数组有着密切的关系,任何能由数组下标完成的操作也都可用指针来实现,但程序中使用指针可使代码更紧凑、更灵活,
一、指向数组元素的指针
我们定义一个整型数组和一个指向整型的指针变量:
int a[10], *p;
和前面介绍过的方法相同,可以使整型指针p指向数组中任何一个元素,假定给出赋值运算
p=&a[0];
此时,p指向数组中的第0号元素,即a[0],指针变量p中包含了数组元素a[0]的地址,由于数组元素在内存中是连续存放的,因此,我们就可以通过指针变量p及其有关运算间接访问数组中的任何一个元素。
Turbo C中,数组名是数组的第0号元素的地址,因此下面两个语句是等价的
p=&a[0];
p=a;
根据地址运算规则,a+1为a[1]的地址,a+i就为a[i]的地址。
下面我们用指针给出数组元素的地址和内容的几种表示形式:
(1). p+i和a+i均表示a[i]的地址, 或者讲,它们均指向数组第i号元素, 即指向a[i]。
(2). *(p+i)和*(a+i)都表示p+i和a+i所指对象的内容,即为a[i]。
(3). 指向数组元素的指针, 也可以表示成数组的形式,也就是说,它允许指针变量带下标, 如p[i]与*(p+i)等价。
假若: p=a+5;
则p[2]就相当于*(p+2), 由于p指向a[5], 所以p[2]就相当于a[7]。而p[-3]就相当于*(p-3), 它表示a[2]。
二、指向二维数组的指针
1.二维数组元素的地址
为了说明问题, 我们定义以下二维数组:
int a[3][4]={{0,1,2,3}, {4,5,6,7}, {8,9,10,11}};
a为二维数组名,此数组有3行4列, 共12个元素。但也可这样来理解,数组a由三个元素组成:a[0],a[1],a[2]。而每个元素又是一个一维数组, 且都含有4个元素(相当于4列),例如,a[0]所代表的一维数组所包含的 4 个元素为a[0][0], a[0][1], a[0][2], a[0][3]。如图所示:
______ _______________
a---| a[0] | ____ | 0 | 1 | 2 | 3 |
|______| |___|___|___|___|
| a[1] | ____ | 4 | 5 | 6 | 7 |
|______| |___|___|___|___|
| a[2] | ____ | 8 | 9 | 10| 11|
|______| |___|___|___|___|
但从二维数组的角度来看,a代表二维数组的首地址,当然也可看成是二维数组第0行的首地址。a+1就代表第1行的首地址,a+2就代表第2行的首地址。如果此二维数组的首地址为1000,由于第0行有4个整型元素,所以a+1为1008,a+2也就为1016。如图所示
_______________
(1000) ____ | 0 | 1 | 2 | 3 |
|___|___|___|___|
(1008) ____ | 4 | 5 | 6 | 7 |
|___|___|___|___|
(1016) ____ | 8 | 9 | 10| 11|
|___|___|___|___|
既然我们把a[0],a[1],a[2]看成是一维数组名,可以认为它们分别代表它们所对应的数组的首地址,也就是讲,a[0]代表第 0 行中第 0 列元素的地址,即&a[0][0], a[1]是第1行中第0列元素的地址,即&a[1][0],根据地址运算规则,a[0]+1即代表第0行第1列元素的地址,即&a[0][1],一般而言,a[i]+j即代表第i行第j列元素的地址, 即&a[i][j],
另外,在二维数组中,我们还可用指针的形式来表示各元素的地址。如前所述,a[0]与*(a+0)等价,a[1]与*(a+1)等价,因此a[i]+j就与*(a+i)+j等价,它表示数组元素a[i][j]的地址。
因此,二维数组元素a[i][j]可表示成*(a[i]+j)或*(*(a+i)+j),它们都与a[i][j]等价,或者还可写成(*(a+i))[j]。
另外, 要补充说明一下, 果你编写一个程序输出打印a和*a,你可发现它们的值是相同的,这是为什么呢? 我们可这样来理解:
首先,为了说明问题,我们把二维数组人为地看成由三个数组元素a[0],a[1],a[2]组成,将a[0],a[1],a[2]看成是数组名它们又分别是由4个元素组成的一维数组。因此,a表示数组第0行的地址, 而*a即为a[0], 它是数组名, 当然还是地址,它就是数组第0 行第0 列元素的地址。
2.指向一个由n个元素所组成的数组指针
在Turbo C中, 可定义如下的指针变量:
int (*p)[3];
指针p为指向一个由3个元素所组成的整型数组指针。在定义中,圆括号是不能少的, 否则它是指针数组, 这将在后面介绍。这种数组的指针不同于前面介绍的整型指针,当整型指针指向一个整型数组的元素时,进行指针(地址)加1运算,表示指向数组的下一个元素,此时地址值增加了2(因为放大因子为2),而如上所定义的指向一个由3个元素组成的数组指针,进行地址加1运算时,其地址值增加了6(放大因子为2x3=6),
这种数组指针在Turbo C中用得较少,但在处理二维数组时, 还是很方便的。例如:
int a[3][4], (*p)[4];
p=a;
开始时p指向二维数组第0行,当进行p+1运算时,根据地址运算规则,此时放大因子为4x2=8,所以此时正好指向二维数组的第1行。和二维数组元素地址计算的规则一样,*p+1指向a[0][1],*(p+i)+j则指向数组元素a[i][j]。
例:
int a[3][4]={
{1,3,5,7},
{9,11,13,15},
{17,19,21,23}
};
main
{
int i,(*b)[4];
b=a+1; /* b指向二维数组的第1行, 此时*b[0]是a[1][0] */
for(i=1;i<=4;b=b[0]+2,i++) /* 修改b的指向, 每次增加2 */
printf(%d\t,*b[0]);
printf(\n);
for(i=0; i<3; i++)
{
b=a+i; /* 修改b的指向,每次跳过二维数组的一行 */
printf(%d\t,*(b[i]+1));
}
printf (\n);
}
程序运行结果如下:
9 13 17 21
3 11 19
三、字符指针
我们已经知道,字符串常量是由双引号括起来的字符序列,例如:
a string
就是一个字符串常量,该字符串中因为字符a后面还有一个空格字符,所以它由8个字符序列组成。在程序中如出现字符串常量C编译程序就给字符串常量按排一存贮区域,这个区域是静态的,在整个程序运行的过程中始终占用,平时所讲的字符串常量的长度是指该字符串的字符个数, 但在按排存贮区域时, C 编译程序还自动给该字符串序列的末尾加上一个空字符'\0',用来标志字符串的结束,因此一个字符串常量所占的存贮区域的字节数总比它的字符个数多一个字节。
Turbo C中操作一个字符串常量的方法有:
篇3:c中指针指针、指针的指针、指针数组和数组指针
一、指针
如果在程序中定义一个变量,在对程序进行编译,系统会自动给这个变量分配内存单元,根据不同的类型,分配不同长度的空间,如int占用4个字节,char占用1个字节,内存单元中每个字节都有编号,这就是地址。由于可通过地址能够找到所需的变量单元,可以说地址指向该变量单元。打个比方,一个房间的门口挂了一个房间号301,这个301就是房间的地址,将该地址形象化为指针。对于一个内存单元来说,单元的地址(编号)即为指针,其中存放的数据才是该单元的内容。
严格地说,一个指针是一个地址,是一个常量,
而一个指针变量却可以被赋予不同的指针值,是变量。但常把指针变量简称为指针。为了避免混淆,约定:“指针”是指地址,是常量,“指针变量”是指取值为地址的变量。定义指针的目的是为了通过指针去访问内存单元。
例如:
int a=12;
int *p=&a;
二、指针的指针(二级指针)
简单来说,二级指针变量就是一级指针变量的地址。
例如:
int a=12;
int *p=&a;
int **=&p;
篇4:C语言其实不简单:数组与指针
之前在写C的时候,没怎么留意数组,就这么定义一个,然后颠来倒去的使用就行了,不过后来碰到了点问题,解决后决定写这么一篇博客,数组离不开指针,索性就放一起好了。
现在我定义了一个数组:int cc[10];
围绕这个数组有好几种指针:cc, cc+1, &cc[0], &cc, &cc+1等等。你知道它们都是什么含义吗?试试运行以下带代码:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include
int main
{
int cc[10];
printf(“%x\n”, cc);
printf(“%x\n”, cc+1);
printf(“%x\n”, &cc[0]);
printf(“%x\n”, &cc);
printf(“%x\n”, &cc+1);
getchar();
return 0;
}
cc,这是学数组时第一个接触的“指针”,最为熟悉,它是数组的首个元素。cc+1,这是指向数字第二个位置的指针。
&cc[0],这个其实就是cc,指向数组的首个元素。
&cc,这是什么玩意儿?指向指针的指针?
&cc+1,如果上面的意思是指向指针的指针,那这个岂不是指向野地址了?
假设运行环境是32位机,并且数组首地址为0x28ff00,那么:
cc的结果为0x28ff00,这点毫无疑问。
cc+1的地址是0x28ff04而不是0x28ff01,因为一个int占用了4个字节的空间。cc+1其实是当成cc+1*sizeof(int)来看待。
&cc[0]的结果是0x28ff00,cc[0]表示的是数组的首个元素,那么&cc[0]自然就是首个元素的地址了。&cc[0] == cc。
&cc,这个就难说了,指针cc的值是0x28ff00,&cc表示这个指针本身的地址,我们怎么可能会知道这个地址?输出是个随机地址吗?随机数的话这个输出完全没有意义啊。如果不是随机地址的话,难不成还是0x28ff00?这样的话a不就等于&a了?明显不对吧,
。。
对于基本类型的指针,如int *tt; 那么*tt是其值,&tt是指针的地址,&tt != tt
但是上述的cc是个数组,实际上,&cc被编译成了&cc[0],但是其含义不同,&cc指向的是整个数组的开头。&cc与cc的指向可以用下图来形象表示:
上图可以看出,&cc其实代表的是int(*)[10],那么&cc+1就可以理解为cc + sizeof(cc)/4,之所以除以4是因为int型指针++其实是移动了4个字节。
又或者说%cc == cc + sizeof(cc)/4 == cc + 10,所以&cc+1的值为0x28ff28。
可见我们平常使用的数组名,并不能单纯的当成指针看待。数组名的本质是代表数组对象的变量名,是一个左值,是一个不能被改变的左值。但是由于在程序中不保存数组的大小,所以通过数组名只能访问数组的左值,不能访问数组的右值。由于这个原因,数组名在作为右值使用的时候被赋予另外一个新的意义——指向数组第一个元素的指针,这就是array-to-pointer转换规则。根据标准规定,只有当数组名作为sizeof、&运算符的操作数的时候,它是一个左值,其类型为数组类型。除此之外的所有情况,数组名都是一个右值,被编译器自动转换为指针类型,这种情况下我们就说数组名是一个指针,并且是一个指针常量。
接下来是另外一些有趣的东西,我们结合sizeof与数组输出各类值。以下程序的输出结果是什么?建议思考后再运行程序来验证答案。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include
int main()
{
int cc[10];
printf(“%d\n”, sizeof(cc[0]));
printf(“%d\n”, sizeof(cc));
printf(“%d\n”, sizeof(&cc));
printf(“%d\n”, sizeof(int(*)[10]));
getchar();
return 0;
}
sizeof(cc[0]),一个int的大小,输出4,没问题。sizeof(cc),注意不要和上面搞混,这不是数组首地址的指针,cc在这里是左值,其为数组类型,所以结果为40。
sizeof(&cc),这个的答案应该是多少呢?注意了,cc在这里还是左值,其为数组类型,但&cc不同于cc,不管数组怎么复杂它始终是个指针,32位机上指针大小始终是4个字节,所以结果为4。
篇5:(C语言)字符串比较函数,指针数组与数组指针
问题描述:
写一个函数,用于比较两个字符串的比较(string_compare).
程序分析:
(1)主要思想:传入两个字符串后,比较这两个字符串中的每个元素,如果第一次比较就不相等,就不要让它进入到下面的比较中,这样一来,将它返回一个相减的值(即:两数组中开始不相等的那两个元素相减,返回值(int类型),是ASCII码值相减)。进入比较的过程中时,相等就返回0;其他情况都返回那个相减的值。
(2)主要方式:定义指针数组,并对其初始化。然后照上面的思想,进行代码的实现。
代码如下:
/***指针数组(1)int *a[10] 是一个指针数组--->是一个数组(每个数组中的元素都是int*类型)(2)int (*a)[10] 是一个数组指针--->指向一个数组(十个int类型的数组) 注意:*,[],的优先级依次递增。下面使用了指针数组的例子,至于数组指针。。**/#include
篇6:数组和指针再次来袭
1,数组和指针的定义于声明:
定义:只能出现一次,用来确定对象的类型和大小,并为其分配空间,
声明:可以出现多次,描述对象的类型,用于指定其他地方定义的对象,不为对象分配空间。
所以说extern char a[]与extern char a[10]等价,因为这是声明,不分配空间。
看一个关于数组指针的例子:
例1:
#include 如果将&a强制类型转换为(char (*)[4])&a后就可以赋值给char (*p)[4]了,p4+1相当于加了4个字节,而不是5,因为p4的大小为4。 例2: #include 结果分析:p的地址为1ef7f4,p里面存放的是结构体的地址,所以p+0x1就要加一个结构体的大小20,转换为16进制,结果就是1ef808, 将p转化为无符号长整型,加1就是直接加十进制1,结果就是1ef7f5。将p转换为整型指针,占四个字节,加1就相当于加1*sizeof(int *),结果就是1ef7f8。 例3:vs中小端存储: int main(){ int a[4] = { 1, 2, 3, 4 }; int *ptr1 = (int *)(&a + 1); int *ptr2 = (int *)((int)a + 1); printf(“%x,%x”, ptr1[-1], *ptr2); system(“pause”); return 0;} 经常遇到这两个概念,很容易混淆,这里细细总结一下, 指针数组:是一个数组,数组的元素是指针。数组占多少个字节由数组本身决定。 数组指针:是一个指针,它指向一个数组。在32位系统下永远是占4 个字节。 举例说明: 1)int *p1[n]; 2)int (*p2)[n]; 1)“[]”的优先级比“*”要高。p1 先与“[]”结合,构成一个数组的定义,数组名为p1,int *修饰的是数组的内容,即数组的每个元素, 即p1是指针数组,其包含n个指向int 类型数据的指针。 2)“”的优先级比“[]”高,“*”号和p2 构成一个指针的定义,指针变量名为p2,int 修饰的是数组的内容,即数组的每个元素。数组在这里并没有名字,是个匿名数组。即p2是数组指针,它指向一个包含n 个int 类型数据的数组。 如要将二维数组赋给一指针,应这样赋值: int a[3][4]; int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。 p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0] p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][] 所以数组指针也称指向一维数组的指针,亦称行指针。 写个简单的yuv读取的库,卡在多维数组动态分配的问题上,唉,还是C基本功不扎实,于是花了一下午时间,算是给自己有了点交代。参考《C专家编程》。水平有限,欢迎看客指正。 Section 1 左值与右值 编译器为每个变量分配一个地址(左值),该地址在编译时可知,且变量在运行时一直存于该地址。存于该地址的变量的值(右值)只有在运行时可知。因此,编译器如果需要一个地址来执行某种操作,它可以直接进行操作,如果需要一个变量的值,它需要发出指令从指定地址中读入变量值并存于寄存器中。到这里,可以理解作为一个指针变量,它本身的地址是左值,它变量的值(即指向的地址值)为右值。所以指针首先需要在运行时取得它的当前值,然后才能对它进行解除引用操作。 数组名是一个左值,即内存中的位置。但数组名是一个不可修改的左值,即不可被赋值。 int main() { int a[3] = {0}; int b = 1; a = &b; //ERROR: “=” : 左操作数必须为 l 值。 return 0; } Section 2 数组与指针的不同 一个例子: int main() { char arr[4] = “abc”; // Note 1 //char arr[4] = {''a'', ''b'', ''c'', ''\0''}; // Note 2 char *ptr = “ABC”; // Note 3 //ptr+1 = &arr[2]; // Note 4 printf(“arr: %x, %x, %x %x \n”, &arr, &arr[0], &arr[1]); //Note 5 printf(“ptr: %x, %x, %x %x \n”, &ptr, &ptr[0], &ptr[1]); return 0; } Note 1&2等价定义,其结构如下: a b c \0 [__] [__] [__] [__] 12fed4 +1 +2 +3 Note 3结构如下 42703c A B C \0 [__] [__] [__] [__] [__] 12fec8 42703c +1 +2 +3 Note 4复习一下Section 1.显然的错误,因为p+1首先需要知道p的值(右值),只有在运行时刻才能得到,编译时刻就希望对其所在的地址进行赋值显然错误, Note 5验证Note1和3,运行结果如下: arr: 12fed4, 12fed4, 12fed5 ptr: 12fec8, 42703c, 42703d 可以发现,arr的地址(左值)的结果与数组中首元素的地址一致,而ptr的变量值(右值)与数组的首元素地址一致。 因此对一个数组中的元素进行引用,c=arr[i]和c=ptr[i]都能够取出相应数组中的第i个元素。但要注意这两个操作的过程完全不同: c = arr[i]; c = ptr[i]; 1:取地址12fec8的内容,即42703c 1 取出i的值与12fed4相加 2:取出i的值与42703c相加 2 取地址(12fed4+ i)的内容 3:取地址(42703c+i)的内容 得到结论:尽管c=arr[i]和c=ptr[i]用同样的形式完成了同样的功能,但绝不可以混用。注意数组原始的声明方式,如果原始声明为数组式的,那么对其元素的引用要使用数组形式,反之亦然。 文件1中: ★ C和指针 (pointers on C)――第十二章:使用结构和指针 ★ C笔试题及答案 ★ C语言笔试题目 【小小的C语言问题指针数组赋值关于指针和数组。(共8篇)】相关文章: 提高计算机专业C语言教学效果的方法探讨2023-06-01 大学c语言学习心得体会2023-04-22 计算机二级c语言试题及答案2022-11-07 计算机二级c语言试题2022-04-29 9月计算机二级考试C语言预测试题2022-04-30 安全员c考试试题及答案2022-04-29 计算机二级c语言答案2022-04-29 C语言嵌套注释2022-09-23 检讨书?c2022-05-08 C语言中的复数C基础2023-05-27篇7:再谈指针数组与数组指针
篇8:深度理解C语言的指针与数组