1. 数组和指针之间的关系?
答:变量在内存存放是有地址的,数组在内存存放也同样具有地址。对于数组来说,数组名就是数组在内存存放的数组首元素地址。指针变量是用于存放变量的地址,可以指向变量,当然也可存放数组的首址或数组元素的地址,这就是说,指针变量可以指向数组或数组元素对数组而言,数组和数组元素的引用,也同样可以使用指针变量。
2. 数组作为参数传递给函数时,可以通过sizeof得到数组的大小吗?
答:不可以。因为函数的数组参数相当于指向该数组第一个元素的指针。有两种方法告诉函数数组参数的大小。
将数组和表示数组大小的值一起传递给函数。例如,memcpy()函数
char source[MAX], dest[MAX];
Memcpy(dest, source, MAX);
引入某种规则来结束一个数组。例如,在C语言中字符串总是以’\0’结束的,而指针数组总是以空指针结束的。
3. array_name和 &array_name有什么不同?
答:前者是指向数组中第一个元素的指针,后者是指向整个数组的指针。
4. 字符串和数组有什么不同?
答:数组的元素可以是任意一种类型,而字符串是一种别的数,它使用了一种众所周知 、确定长度的规则。
根据处理字符串的不同,语言可分为两种,一种是简单地将字符串看作一个字符数组,另一种是将字符串看作一种特别的类型。C语言属于前一种,但有一点补充,即C字符串是以一个NUL字符结束的。数组的值和数组中第一个元素的地址(或指向该元素的指针)是相同的。
数组的长度可以是任意的,当数组名用作函数的参数时,函数无法通过数组名本身相同的知道数组的大小,因此必须引入某种规则。对字符串来说,这种规则就是字符串的最后一个符是ASCII字符“NUL(‘\0’)”
5. 回调函数
回调函数是一个通过函数指针调用的函数。如果你把函数指针(函数的入口地址)传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
6. 指针的运算
答:指针加上一个整数的结果是另一个指针。问题是:它指向哪里?如果将一个字符指针加运算结果产生的指针指向内存中的下一个字符。foat占据的内存空间不止1个字节,如果将一个指向foat的指针加1,将会发生什么?它会不会指向该float值内部的某个字节呢?
幸运的是,答案是否定的。当一个指针和一个整数量执行算法运算时,整数在执行加法运算之前始终会根据合适的大小进行调整。这个“合适的大小、”就是指针所指向类型的大小“调整”就是把整数值和“合适的大小”相乘。例如,某台机器上,foat占4个字节,在运算foat型指针加3的表达式时,这个3将根据foat类型的大小(此例中为4)进行调整(相乘)。这样实际加到指针上的整数值为12。把3与指针相加使指针的值增加3个foat的大小,而不是3个字节。
7. 指针变量或数组名作为函数参数
答:指针变量作实参在调用时仍然符合前述“值传递”规则,将其“值”赋给形参,相当于复制。此时数据在实参与形参间传递仍是单向的,两用需数不会影响实参的“值”(即指针变量中所存地址)。而与简单变量不同的是,指针变量复制给形参的“值”本身是一个地址,这个地址为形参访问其所指变量创造了可靠条件。我的理解是,实参是一个抽屉的钥匙,在传参时,实参复制了一把钥匙传给形参,而被调函数拿到钥匙副本后,进行的操作可以分为两类
(1)对钥匙本身做了一些操作(对指针本身进行操作)
(2)通过钥匙对抽屉里的内容进行了一些操作(对指针所指的变量进行操作)。两种操作都不可能影响实参的值(即钥匙原本),却有可能改变实参所指向变量的值(即抽屉里的内容)
# include<stdio.h>
int main ( )
{
void swap(int *p1, int *p2)
int a, b;
int *pointer1, int *pointer2
scanf(“%d %d”, &a, &b);
pointer = &a;
pointer = &b;
if (a < b)
{
swap (pointer1, pointer2);
}
printf(“%d %d\n”,a ,b);
return 0;
}
void swap( int *pl, int *p2 )
{
int temp;
temp = *p1;
*pl = *p2 ;
*p2 = temp;
}
# include<stdio.h>
int main ( )
{
void swap(int *p1, int *p2)
int a, b;
int *pointer1, int *pointer2
scanf(“%d %d”, &a, &b);
pointer = &a;
pointer = &b;
if (a < b)
{
swap (pointer1, pointer2);
}
printf(“%d %d\n”,a ,b);
return 0;
}
void swap( int *pl, int *p2 )
{
int temp;
temp = p1;
pl = p2 ;
p2 = temp;
}
8. 结构体数组作函数参数实参
答:用结构体数组作包含两类情况:结构体数组元素作为实参和结构体数组名作为实参。两类情况仍然服从数据的单向值传递原则,只不过前者传给形参的是某些变量的值后者传给形参的是结构体数组的首地址。
① 结构体数组元素作为实参
符合结构体变量作为实参规则,采取单向“值传递”方式将结构体变量所占的内存单元的内容全部顺序复制给形参(函数调用期间形参也要占用内存单元)。注意,当实参的成员中包含数组时,形参相应的成员接收到的是一个地址
② 结构体数组名作为实参
同整型数组数组名作为实参一样,传递给形参的是内存中已指定单元的地址,调用过程中形参数组与实参数组占用同一段内存单元,因此对形参数组的操作也就是对实参数组的操作,对数组的操作表现为双向性综上所述,在有参函数调用时,实参变量与形参变量之间的数据都是单向“值传递”方式至于调用过程中是否会改变主调函数中变量的值,则只需根据具体算法看被调函数是否会找到主调函数中变量所在内存单元并对其原本进行操作
9. 函数指针
答:在C语言中,一个函数总是占用一段连续的内存区,而函数名就是该函数所占内存区的首地址。我们可以把函数的这个首地址(或称入口地址)赋予一个指针变量,使该指针变量指向该函数。然后通过指针变量就可以找到并调用这个函数。我们把这种指向函数的指针变量,称为“函数指针变量”。
函数指针变量定义的一般形式为:
类型说明符 (*指针变量名)();
其中“类型说明符”表示被指函数的返回值的类型。“(*指针变量名)”表示“*”后面的变量是定义的指针变量。最后的空括号表示指针变量所指的是一个函数。
例如:
int (*pf)();
表示 pf是一个指向函数入口的指针变量,该函数的返回值(函数值)是整型。
本例用来说明用指针形式实现对函数调用的方法。
int max(int a,int b)
{
if(a>b)return a;
else return b;
}
main(){
int max(int a,int b);
int(*pmax)();
int x,y,z;
pmax=max;
printf("input two numbers:\n");
scanf("%d%d",&x,&y);
z=(*pmax)(x,y);
printf("maxmum=%d",z);
}
从上述程序可以看出用,函数指针变量形式调用函数的步骤如下:
1)先定义函数指针变量,如后一程序中第 9 行 int (*pmax)();定义pmax 为函数指针变量。
2)把被调函数的入口地址(函数名)赋予该函数指针变量,如程序中第11 行pmax=max;
3)用函数指针变量形式调用函数,如程序第 14 行 z=(*pmax)(x,y);
4)调用函数的一般形式为:
(*指针变量名) (实参表)
使用函数指针变量还应注意以下两点:
a)函数指针变量不能进行算术运算,这是与数组指针变量不同的。数组指针变量加减一个
整数可使指针移动指向后面或前面的数组元素,而函数指针的移动是毫无意义的。
b)函数调用中"(*指针变量名)"的两边的括号不可少,其中的*不应该理解为求值运算,在此处它只是一种表示符号。
10. 指针型函数
答:前面我们介绍过,所谓函数类型是指函数返回值的类型。在C语言中允许一个函数的返回值是一个指针(即地址),这种返回指针值的函数称为指针型函数。
定义指针型函数的一般形式为:
类型说明符 *函数名(形参表)
{
…… /*函数体*/
}
其中函数名之前加了“*”号表明这是一个指针型函数,即返回值是一个指针。类型说明符表示了返回的指针值所指向的数据类型。
如:
int *ap(int x,int y)
{
...... /*函数体*/
}
表示 ap是一个返回指针值的指针型函数,它返回的指针指向一个整型变量。