指针—— char p[] 和 char *p

目录

1. char p[]和char *p   ☆☆☆☆

2. 

3.  函数里的指针**

4.数组作为函数参数传递

5. 两数交换的那些坑 

 6. 函数参数为指针应小心

7. 数组指针 **

8. 二级指针

9. *p++、 (*p)++、 *++p、 ++*p


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

  • 7
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值