c语言指针编程面试题,关于C语言的15个指针面试题

1. 常指针与常量的指针

char * const p;

char const * p

const char *p

上述三个有什么区别?

char * const p;   //p为只读指针。

char const * p;//p值只读的指针。

const char *p; //和char const *p

---------------------------------------------------

2.定义与声明

声明是普通的声明:它所描述的并非自身,而是描述在其他地方创建的对象。

定义是特殊的声明:它为对象分配内存,即现场创建对象。

---------------------------------------------------

3.左值与右值

I.左值:编译时可知。左值可以分为可修改左值和不可修改左值,数组名就是一个不可修改的左值。即不能给数组名赋值!(注意这里指的是“数组名”) 这是为什么呢?下面有一个现场:

char a[10] = {'a'};

char b[10] = {'b'};

a = b;

编译时出现的错误:

error: incompatible types when assigning to type ‘char[10]’ from type ‘char *’

结论:

当数组名为左值时,它的类型是字符数组;当数组名为右值时,它的数据类型是字符指针。

II.右值:运行时可知。

---------------------------------------------------

4.指针与数组

如果编译器需要一个地址来执行一种操作,对于被定义的数组变量而言的,它地址在编译时可知,所以它就可以直接进行操作;而对于被声明的指针而言,只有在程序运行的时候才知道它所指向的地址的值,然后才能在当前地址上操作。

char array[] = “sdfsdf”;   …   c = a[i];

数组的下标引用步骤:(1)取编译器符号中的符号array的地址(假设是8888)

(2)array[i]即为取地址8888+i的内容。

char *p; … c = *p;

指针的间接引用步骤:(1)取编译器符号表中符号p的地址(假设是7777)

(2)获取7777位置处的内容(假设是9999)

(3)取9999处地址的内容,即为*p

char *p = “abcdefg”;

char a[] =“abcdefg”;

那么,p[i]与a[i]的区别?

a[i]是直接在(符号表a的地址+i)处获取内容,即为直接引用。

p[i]是先获取符号表p地址的内容,然后在该内容上+i地址处获取内容,即为间接引用。这里的“间接”指的是要被操作的地址不能直接从编译器符号表中直接获得,而是从指针对象中获得。

char str1[] = "abc";

char str2[] = "abc";

const char str3[] = "abc";

const char str4[] = "abc";

const char *str5 = "abc";

const char *str6 = "abc";

char *str7 = "abc";

char *str8 = "abc";

cout << ( str1 == str2 ) << endl;

cout << ( str3 == str4 ) << endl;

cout << ( str5 == str6 ) << endl;

cout << ( str7 == str8 ) << endl;

打印结果是什么?

解答:结果是:0 0 1 1

str1,str2,str3,str4是数组名,各表示一个数组变量(即对象变量),它们有各自的内存空间;而str5,str6,str7,str8是指针变量,它们指向相同的常量区域。不同的对象之间当然不可能相等,而指向相同区域的指针变量是相等的。

-----------------------------------------------

5. sizeof()函数

以下代码中的两个sizeof用法有问题吗?

void UpperCase( char str[] ){ // 将 str 中的小写字母转换成大写字母

int i;

for( i = 0; i < sizeof(str)/sizeof(str[0]); ++i ){

if(str[i] >= 'a' && str[i] <= 'z')

str[i] -= ('a'-'A' );

}

}

int main(){

char str[] = "aBcDe";

printf("str字符长度为: %lu/n", sizeof(str)/sizeof(str[0]));

UpperCase( str );

printf("%s/n", str);

}

答:函数内的sizeof有问题。

根据语法,sizeof只能测出定义的对象,不能测出声明的变量。静态数组是定义的对象,可以测出;而在函数内,str只是一个声明的变量,非定义的对象,故不能测出。

在gcc4.4.5/x86_64-linux-gnu环境下有,

sizeof(char*)=8

sizeof(int*)=8

所以,这里可以得到正确的结果,但是有时候,可能出现数组越界的情况。

-------------------------------------------------

6.C不进行数组 的下标检查,地址可以越界,间接访问的时候可能出现“段错误”:

int a[5]={1,2,3,4,5};

int *ptr=(int *)(&a+1);

printf("%d,%d/n",*(a+1),*(ptr-1));

输出结果是什么?

答案:输出:2,5

*(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5

&a+1不是首地址+1,系统会认为加一个a数组的偏移,是偏移了一个数组的大小(本例是5个int)

&a是数组指针,其类型为 int (*)[5];

--------------------------------------------

7.strcpy()函数:

int main(){

char a;

char *str=&a;

strcpy(str,"hello");

printf("%s/n", str);

}

答案:没有为str分配内存空间,将会发生异常。问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。

---------------------------------------------

8.指针的间接引用

分析下面代码的问题:

char* s="AAA";

printf("%s",s);

s[0]='B';

printf("%s",s);

分析:对象s的内容,是一个常量字符串“AAA”内存空间的首地址。s[0]='B'这一句,表示给一个字符常量赋值,显然是不合法的。

---------------------------------------------

9. int (*s[10])(int) 表示的是什么?

答案:int (*s[10])(int) 函数指针数组,每个指针指向一个int func(int param)的函数。

---------------------------------------------

10. 传值函数,对主函数中的变量没有影响

void getmemory(char *p){

p=(char *) malloc(100);

strcpy(p,"hello world");

}

int main(){

char *str=NULL;

getmemory(str);

printf("%s",str);

printf("/n");

free(str);

return 0;

}

在getmemory()函数中,参数p充当一个行参。在主函数中,free()操作一个空指针,不会起任何作用。

------------------------------------------

11.要对绝对地址0x100000赋值,我们可以用*((unsigned int*)0x100000) = 1234;

那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做?

这里必须要注意:有方法分配指定区域的内存,是给绝对地址赋值的前提条件。纠结的是,C没有提供分配指定区域内存的方法。

答案:*((void (*)( ))0x100000 ) ( );

首先要将0x100000强制转换成函数指针,即:

(void (*)())0x100000

然后再调用它:

*((void (*)())0x100000)();

用typedef可以看得更直观些:

typedef void(*)() voidFuncPtr;

*((voidFuncPtr)0x100000)();

------------------------------------------

12. 分析下面的程序:

void GetMemory(char **p,int num){

*p = malloc(num);

}

int main()

{

char *str=NULL;

GetMemory(&str,100);

strcpy(str,"hello");

free(str);

if(str!=NULL){

printf("%X/n", str);

}

}

问输出结果是什么?

答案:输出的是指针对象str的值。在个指针分配内存的时候,其实给指针对象赋了一个值,这个值就是这片空间的首地址。释放空间后,这个指针对象的值,其实是指向没有被分配空间的地址。访问这样的越界空间,编译是没有问题的,但是运行时编译器出现“Segmentation fault”.

-------------------------------------------

13.分析下面程序的结果:

int main()

{

char a[10];

printf("%d",strlen(a));

}

答案:0,这由strlen()函数的内部实现有关。

--------------------------------------------

14.char (*str)[20];

char *str[20];

---------------------------------------------

15.分析下面代码:

typedef struct AA{

int b1 : 5;

int b2 : 2;

}AA;

void main()

{

AA aa;

printf("%d/n", 'A');

char cc[100];

strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");

memcpy(&aa,cc,sizeof(AA));//将sizeof(AA)个连续的字节空间(从cc开始),源和目的地不能重叠

printf("%d %d/n", aa.b1, aa.b2);

}

首先sizeof(AA)的大小为4,b1和b2分别占5bit和2bit.经过strcpy和memcpy后,aa的4个字节所存放的值是: 0,1,2,3的ASC码,即00110000,00110001,00110010,00110011所以,最后一步:显示的是这4个字节的前5位,和之后的2位分别为:10000,和01,因为int是有正负之分

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值