大家好,欢迎来到IT知识分享网。
目录
c语言-数组、指针面试题 – CYYZ古月 – 博客园 ☆☆☆☆☆☆
char *p=”abc” 与 char p[]=”abc” 的区别_安徽祝子的博客-CSDN博客
C++ 常量 | 菜鸟教程
1. char p[]和char *p ☆☆☆☆
char str[] = "hello"; // 将字符串常量拷贝到了变量内存 str[0] = 's'; //合法 char *str = "hello"; //字符串存储在静态存储区 p[0] = 's'; //不合法
这两个都可以成功编译,只是第二个会在运行时期出现段错误。首先”hello”是一个字符串常量,存储在静态数据区域(data段),这是在编译时期就确定的。第一个是将字符串常量赋值给了一个变量(全局变量在数据段,局部变量在栈区),实际上是将字符串常量拷贝到了变量内存中,因此修改的只是str[]这个变量的值。第二个是将字符串常量的首地址赋值给p,对p操作就是对字符串常量进行修改!因此出现了段错误。
2.
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; // 0 cout << ( str3 == str4 ) << endl; // 0 cout << ( str5 == str6 ) << endl; // 1 cout << ( str7 == str8 ) << endl; // 1
- str1 str2 str3 str4是数组名,也是数组首元素的地址。编译器给他们分配了新的存储空间来对字符串”abc”进行拷贝,这些变量在内存里是相互独立的,因此他们的地址肯定不同!
- str5,str6,str7,str8 是指针,他们的值就是字符串常量的地址!它们都指向“abc”所在的静态数据区,所以他们都相等。
3. 函数里的指针
#include <stdio.h> char *returnStr() { char p[]="hello world!"; return p; //p 是局部变量,将字符串拷贝在栈区 } //函数退出时,栈被清空,p被释放 int main() { char *str = NULL; str = returnStr(); //返回的是被释放的地址 printf("%s\n", str); return 0; }
因此返回的是被释放的地址!!!下面为修改方式:
#include <stdio.h> char *returnStr() { char *p = "hello world!"; return p; //字符串存储在静态存储区 } int main() { char *str = NULL; str = returnStr(); printf("%s\n", str); return 0; }
4.数组作为函数参数传递
int func(int a[]) { int n = sizeof(a)/sizeof(int); for(int i=0;i<n;i++) { printf("%d ",a[i]); a[i]++; } }
将数组传递给一个函数时,无法按值传递,而是会自动退化为指针。下面的三种写法其实是等价的:”int func(int a[20]);” 等价于 “int func(int a[]);” 等价于 “int func(int *a);”。
5. 两数交换的那些坑
void swap(int* a, int* b) { int *p; p = a; a = b; b = p; } // 错误
void swap(int* a, int* b) { int tmp; tmp = *a; *a = *b; *b = tmp; } //正确
a和b虽然也是副本,但是在函数内部通过该地址直接修改了对象的值,对应的实参就跟着发生了变化。
其实,指针传递和值传递的本质都是值传递,值传递是传递了要传递变量的一个副本。复制完后,实参的地址和形参的地址没有任何联系,对形参地址的修改不会影响到实参,但是对形参地址所指向对象的修改却能直接反映在实参中,这是因为形参所指向的对象就是实参的对象。正因如此,我们在传递指针作为参数时,要用const进行修饰,就是为了防止形参地址被意外修改。
6. 函数参数为指针应小心
void GetMem(char *p) { p = (char*)malloc(100); } //对实参没有影响 void main() { char *str = NULL; GetMem(str); strcpy(str, "hello word!"); printf(str); }
程序崩溃。在上面已经分析过了,传递给GetMem函数形参的只是一个副本,修改形参p的地址对实参str丝毫没有影响。所以str还是那个str,仍为NULL,这时将字符串常量拷贝到一个空地址,必然引发程序崩溃。
void GetMem(char p) { *p = (char*)malloc(100); } void main() { char *str = NULL; GetMem(&str); strcpy(str, "hello word!"); printf(str); free(str); //不free会引起内存泄漏 }
让指针变量str指向新malloc内存的首地址,也就是把该首地址赋值给指针变量str。前面我们说过,指针传递本质上也是值传递,要想在子函数修改str的值,必须要传递指向str的指针,因此子函数要传递的是str的地址,这样通过指针方式修改str的值,将malloc的内存首地址赋值给str。
7. 数组指针
int *p1[10]; // 指针数组,数组的元组都是指针 int (*p2)[10]; //数组指针,是一个指针,指向一个数组
int a[5] = { 1, 2, 3, 4, 5 }; int *ptr = (int *)(&a + 1); printf("%d,%d", *(a + 1), *(ptr - 1)); // 2 , 5
”+1“就是偏移量的问题:一个类型为T的指针移动,是以sizeof(T)为单位移动的。
a+1:在数组首元素地址的基础上,偏移一个sizeof(a[0])单位。因此a+1就代表数组第1个元素,为2;
&a+1:在数组首元素的基础上,偏移一个sizeof(a)单位,&a其实就是一个数组指针,类型为
int(*)[5]。因此&a+1实际上是偏移了5个元素的长度,也就是a+5;再看ptr是int*类型,因此“ptr-1″就是减去sizeof(int*),即为a[4]=5;
a是数组首地址,也就是a[0]的地址,a+1是数组下一个元素的地址,即a[1]; &a是对象的首地址,&a+1是下一个对象的地址,即a[5]。
8. 二级指针
给定声明 const char * const *pp;下列操作或说明正确的是?
(A)pp++ (B)(*pp)++ (C)(pp)=\\c\\; (D)以上都不对
一级指针:
(1)const char p : 限定变量p为只读。这样如p=2这样的赋值操作就是错误的。
(2)const char *p : p为一个指向char类型的指针,const只限定p指向的对象为只读。这样,p=&a或 p++等操作都是合法的,但如*p=4这样的操作就错了, 因为企图改写这个已经被限定为只读属性的对象。
(3)char *const p : 限定此指针为只读,这样p=&a或 p++等操作都是不合法的。而*p=3这样的操作合法,因为并没有限定其最终对象为只读。
(4)const char *const p :两者皆限定为只读,不能改写。
(1)const char p : p为一个指向指针的指针,const限定其最终对象为只读,显然这最终对象也是为char类型的变量。故像p=3这样的赋值是错误的, 而像*p=? p++这样的操作合法。
(2)const char * const *p :限定最终对象和 p指向的指针为只读。这样 *p=?的操作也是错的,但是p++这种是合法的。
(3)const char * const * const p :全部限定为只读,都不可以改写
9. *p++、 (*p)++、 *++p、 ++*p
int a[5]={1, 2, 3, 4, 5}; int *p = a;
*p++ 先取指针p指向的值(数组第一个元素1),再将指针p自增1;
cout << *p++; // 结果为 1 cout <<(*p++); // 1
(*p)++ 先去指针p指向的值(数组第一个元素1),再将该值自增1(数组第一个元素变为2
cout << (*p)++; // 1 cout <<((*p)++) // 2
*++p 先将指针p自增1(此时指向数组第二个元素),* 操作再取出该值
cout << *++p; // 2 cout <<(*++p) // 2
++*p 先取指针p指向的值(数组第一个元素1),再将该值自增1(数组第一个元素变为2)
cout <<++*p; // 2 cout <<(++*p) // 2
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/109820.html
![指针—— char p[] 和 char *p插图1 指针—— char p[] 和 char *p](https://i-blog.csdnimg.cn/blog_migrate/85bbee458d4a3b9e9df564a20f6144d6.png)
![指针—— char p[] 和 char *p插图3 指针—— char p[] 和 char *p](https://i-blog.csdnimg.cn/blog_migrate/94e885a8d40d96bccc4b9f96dae4eb14.png)
![指针—— char p[] 和 char *p插图5 指针—— char p[] 和 char *p](https://i-blog.csdnimg.cn/blog_migrate/bda36160376670d2cd622981750e1f50.png)