精华内容
下载资源
问答
  • 字符数组与字符串常量
    2014腾讯实习生笔试题:有以下两个函数,调用test的结果是()  
    
    char* getMem(void)
    {      
    	Char * p = “hello world ”;
    	P[5] = 0x0;
    	Return p;
    }
    void test(void) 
    {      
    	char *s = 0x0;
    	s = getMem();
    	Printf(s);
    }
    A.  hello   B. 无输出  C.  Hello0world   D.  不确定


    首先来分析一下,字符数组与字符串常量区别:

    情景一:char str[]="hello world";
    情景二:char *str="hello world";

    编译器对第一种情况分配一个局部字符数组,而对第二种情况分配一个全局数组。那么

    #include <iostream>
    #include <stdlib.h>
    #include <string.h>
    using namespace std;
    char *strTest();
    int main()
    {
        char *str=NULL;
        str=strTest();
        cout<<str<<endl;
        return 0;
    }
    
    char *strTest()
    {
        char *str="Hello World!";
        return str;
    }
    这段代码,能正确打印出 ”hello world“,而对于以下这段代码

    #include <iostream>
    #include <stdlib.h>
    #include <string.h>
    using namespace std;
    char *strTest();
    int main()
    {
        char *str=NULL;
        str=strTest();
        cout<<str<<endl;
        return 0;
    }
    
    char *strTest()
    {
        char str[]="Hello World!";
        return str;
    }

    程序输出是不确定的,因为字符数组是局部的,对应的是内存的栈,strTest函数结束后,这段内存内容就被释放,所以执行结果是乱码不确定的,

    特别注意:字符常量保存在只读的数据段,也就是说字符串常量的内容是只读而不允许改写的,

    char *str="Hello World!";
    str[1]='a';
    第二行段代码是错误的,运行时会出错,因此腾讯这道题选B(不确定)。


    展开全文
  • //正确 } 总结 主要是看 const 修饰的位置, const int *p 和 int const *p 都是指针常量,因为const 修饰的都是 *p(也就是 p 指向的常量),常量不能被更改,所以指向的内容不能改,但指向的地址能更改 int* const ...

    指针

    一个变量的地址称为该变量的“指针”;

    • 如果说地址是对内存单元的编号,那么指针就是存放内存单元的变量

    简单来说,如果你去宾馆住宿,前台给你门卡并且告诉你房间在 666号,这时候你就能根据前台提供的地址精准的找到属于你自己的房间了。同理,指针就是指向变量的门牌号,通过指针,你就能找到它所指向的变量的地址了了。
    要注意的是:int* p 中,int * ->是整形指针类型, p -> 才是指针, * -> 解应用操作符。
    如果说指针是房间的门牌号,那*就是房间的钥匙。

    int a = 10;
    int *p;
    p = &a;   //p 是指针,它指向变量a存放数据(10)的内存地址
    *p = a = 10;  //对p解应用相当于顺着p指向的地址找到变量(a)存放的数据(10)
    

    一级指针
    一级指针的定义形式一般为:
    类型名 * 指针变量名

    如以下的几种形式:

    int a; // a是变量
    
    int *p;
    p = &a;    
    //or
    int *p = &a;
    
    int a[] = {0,1,2,3,4};   //a是数组
    
    int *p;
    p = &a[0];
    //or
    int *p = a;
    

    一级指针的传参:

    void Ner(int *x, int *y)
    {
    }
    int main()
    {
     int x,y;
     int *p1 = &x;
     int *p2 = &y;
     Ner(p1,p2); //变量的传参
     return 0;
     }
     //****************************
     void Fun(int *str)
     {
     }
     int main()
     {
      int arr[] = {0};
      Fun(arr);   // 数组的传参
      return 0;
      }
    

    二级指针

    二级指针是存放一级指针地址的指针,是 “地址的地址”
    二级指针的传参:

    void test1 (int **p)
    {
    }
    int main()
    {
     int n = 10;
     int *p = &n;  // p是n的地址
     int **pp = &p;   // pp是p的地址
     test1(pp);    // 方式1
     test1(&p);   // 方式2
     return 0;
     }
    

    指针数组

    其一般形式为:
    类型名 * 数组名【数组长度】

    • int *p[10]

    本质上是一个数组,是一个存放指针的数组。也就是说指针数组中的每一个元素都存放着一个地址,相当于一个指针变量。

    数组指针

    其一般形式为:
    类型名 (*)【数组长度】

    • int (*p) [10]

    本质上是一个指针,表示指向数组的指针,即数组首元素地址的指针
    上面的数组指针表示:定义p为一个指针变量,它指向包含10个整形元素的一维数组,即p是指向一维数组的指针。所以数组指针一般用来表示二维数组。

    数组指针的应用:

    int arr[2][3] = {{1,2,3},{4,5,6}};
    //  1 2 3
    //  4 5 6
    *(*(arr+0)+2) = arr[0][2] =3;
    *(*(arr+1)+1) = arr[1][1] = 5;
    

    指针常量和常量指针

    区别

    1、本质

    • 指针常量:本质上一个常量,指针用来说明常量的类型,表示该常量是一个指针类型的常量。
    • 常量指针:本质上是一个指针,常量表示指针指向的内容,说明该指针指向一个“常量”

    2、地址

    • 指针常量:在指针常量中,指针自身的值是一个常量,不可改变,始终指向同一个地址。在定义的同时必须初始化。
    • 常量指针:指针可以指向其他地址

    3、内容

    • 指针常量:指向的内容可以修改,地址不能改
    • 常量指针:在常量指针中,指针指向的内容是不可改变的,指针看起来好像指向了一个常量,但是地址能更改。

    演示

    int main()
    {
    	//这是常量指针,内容不能改,地址能改
    	int a = 10;
    	int b = 20;
    	const int *p = &a;
    	*p = 30;     // 出错
    	p = &b;      //正确
    
    	//这是指针常量,内容能改,地址不能改
    	int* const q = &b;
    	q = &a;      //出错
    	*q = 30;     //正确
    }
    

    总结

    • 主要是看 const 修饰的位置, const int *p 和 int const *p 都是指针常量,因为const 修饰的都是 *p(也就是 p 指向的常量),常量不能被更改,所以指向的内容不能改,但指向的地址能更改
    • int* const p 中 const 修饰的是 p, 而 p 是一个指针,所以 p 指向的地址不能更改,而内容却能够更改
    展开全文
  • 好,现在是要确定两种说法那种正确以下代码是在VC2008下的测试代码。 #include int main() { char *p1 = "P1P1P1P1"; printf("p1=%p\n",p1); char a[]="helloworld"; char *p2 = "P2P2P2P2"; printf("p2...

    首先来看两段代码:

    代码1

    #include<stdio.h>
    
    int main()
    {
    	char str[]="12345";
    	str[2]='A';
    	
    	return 0;
    }

    代码2

    #include<stdio.h>
    
    int main()
    {
    	char *p ="12345";
    	p[2] = 'A';
    	
    	return 0;
    }

    两段代码都能编译通过,但是代码2执行时会报错。其实,其报错的原因很好理解,因为指针p指向的是一块常量区的开始地址,该区域数据是不允许修改的。所以p[2] = 'A'试图改该区内容时会报错。那显然代码2肯定涉及到栈区(p)和常量区("12345")内存的分配。

    那代码1为什么可以呢?,它又涉及到哪些内存区的分配呢?

    我看网上有两种说法:

    一种说法认为char str[]="12345"中的常量"12345"并不在常量区中分配内存,而是直接存在以str开头的栈地址中的,也就是说整个过程不会在常量区中分配内存。

    具体参考博文:http://www.embedu.org/Column/Column540.htm

    另一种说法则认为,char str[]="12345"中的常量"12345"需要在常量区中分配内存,但同时它会拷贝一份副本在以str开头的栈地址中,整个内存中就会有两份"12345"。具体参考文档:http://wenku.baidu.com/view/ea39b8000740be1e650e9a3e.html

    当然,不管是那种说法均能正确解释代码1的正确性。对于说法1,直接在栈中分配内存,根本没有在常量区分配内存,肯定是可以改变其值的。对于说法2,str[2]='A',改变的只是栈中的副本,并不会改变常量区中的值。所以该代码没有问题。

    好,现在是要确定两种说法那种正确,以下代码是在VC2008下的测试代码。

    #include<stdio.h>
    int main()
    {
    	char *p1 = "P1P1P1P1";
    	printf("p1=%p\n",p1);
    
    	char a[]="helloworld";
    
    	char *p2 = "P2P2P2P2";
    	printf("p2=%p\n",p2);
    
    	printf("a=%p\n",a);
    	
    	return 0;
    }

    通过在return语句设置断点,调试结果如下:


    显然p1,p2指向的地址肯定是在常量区的,好,而且如果在常量区中存有"helloworld",因为char a[]="helloworld"语句在char *p1 = "P1P1P1P1"和char *p2 = "P2P2P2P2"之间,所以此时在p1,p2指向地址之间应该存有"helloworld"。通过查找,我们果然查到了。如下图:


    由上图看出在地址0x0106597C中确实存有"helloworld"。看下图更详细。


    好,现在在常量区中确实存在"helloworld",现在看看栈中是否存有它的副本。


    显然,在a指向地址开始出,也有"helloworld"。

    由此,说明第二种说法的正确性。当然,本人只是在VS2008下测试,不知在Linux下是否会一样。

    既然这个问题搞清楚了,我们看一个例子。

    #include<stdio.h>
    
    char * GetStr1()
    {
    	char *s1 = "123456";
    	printf("In GetStr1,s1=%p\n",s1);
    	return s1;
    }
    
    char * GetStr2()
    {
    	char s2[]="123456";
    	printf("In GetStr2,s2=%p\n",s2);
    	return s2;
    }
    
    char * GetPointer()
    {
    	char a ;
    	char *p1 = &a;
    	printf("In GetPointer,p1=%p\n",p1);
    	return p1;
    }
    
    int main()
    {
    	char *str1 = NULL;
    	char *str2 = NULL;
    	char *p = NULL;
    	str1 = GetStr1();
    	printf("str1=%p\n",str1);
    	str2 = GetStr2();
    	printf("str2=%p\n",str2);
    	p = GetPointer();
    	printf("p=%p\n",p);
    	
    	return 0;
    }

    运行结果:


    乍一看,好像完全符合我们的想象。但其实,只有第一个函数是正确的,其他两个函数都是有问题的。第一个函数,函数返回时,将s1所指向的内存地址返回给主函数中的str1。然后由于s1是局部变量,存在栈中,就会释放s1变量本身所占的4字节的内存,但不会释放由于s1所指向的那块内存,因为这块内存是在常量区的,只有当整个程序执行完后OS才会将其释放。而第二个函数,s2所指向的那块内存是常量"123456"在中副本的首地址,当函数返回时,虽然能将该地址返回给str2,由于s2所指向的那块内存是GetStr2()函数中局部变量,但是当函数返回后,该内存区域会被释放,里面的数据将是垃圾数据。第三个函数是初学者最容易出错的,其他它原理,与第二个函数类似。

    关于数组字符串存储的问题,我在CSDN论坛上提问时,碰到一个很有趣的代码,问题链接如下:http://bbs.csdn.net/topics/390440590?page=1#post-394339305

    代码如下:

    int main()
    {
        int i =0, k[10] = {0};
        for(;i <= 10; ++i)
        {
            k[i] = 0;
        }
    }

    发现上面代码竟然是一个死循环。于是,我将该代码增加了几条输出语句。

    #include<stdio.h>
    
    int main()
    {
        int m=1;
        int i =0;
    	int k[10] = {0};
    	printf("&m=%d\n",&m);
    	printf("&i=%d\n",&i);
    	printf("&k[0]=%d\n",&k[0]);
    	printf("&k[9]=%d\n",&k[9]);
    	printf("&k[10]=%d\n",&k[10]);
    
        for(;i <= 10; ++i)
        {
            k[i] = 0;
        }
    	printf("HelloWorld!\n");
    }

    运行结果如下:


    发现k[10]的地址和i的地址竟然是一样的,所以难怪会出现死循环的了,在for循环中,当i10是,此时k[i]k[10]被改为0,也即将i该为0了。

    为什么k[10]的地址和i的地址一样的呢?我们看上面的输出,会发现mik数组三者内存空间是连续的,且m的地址最高,这就是栈(三个变量均存在栈中)。先进后出。编译器先分配10个地址给数组,然后将接下来的地址分配给i,再接下来的地址分配给m。所以才会出现k[10]地址与i的地址相同,而且k[11]的地址肯定是与m的地址相同的。还有要记得k[10]访问通过指针来实现的,就是数组的首地址+10来访问的。也即k[10]等价*(k+10),准确的说,编译器遇到k[i]都会将其用*(k+i)形式代替它来访问内存,这种通过指针的移动效率更高。要注意的是,实际移动的地址是i*sizeof(DataType).


    本文下载地址:http://www.kuaipan.cn/file/id_63913550065731420.htm



    展开全文
  • 其实简单一点讲,“常量指针”所指向的地址上的数据是常量,而“指针常量”所指向的地址是常量,地址上面的数据是可以变化的。 常量指针,就是指向常量的指针,关键字 const 出现在 * 左边,表示指针所指向的地址的...

        其实这个概念比上篇文章中的概念好理解的多。其实简单一点讲,“常量指针”所指向的地址上的数据是常量,而“指针常量”所指向的地址是常量,地址上面的数据是可以变化的。

    常量指针,表述为“是常量的指针”,就是指向常量的指针,关键字const出现在 * 左边,表示指针所指向的地址的内容是不可修改的,但指针自身可变。
    指针常量,表述为“是指针的常量”,指针自身是一个常量,关键字 const 出现在 * 右边,表示指针自身不可变,但其指向的地址的内容是可以被修改的。
    例:
            常量指针: const char* ptr = “hello”
            指针常量: char* const ptr = “hello”
        看关键字靠着谁近,const靠着ptr近说明就是指针常量,就是指针自身不鞥呢变,但所指向的数据可以变;const靠着类型近,说明指针所指向的内容不可变,但是指针可以变
    另外常量指针有两种写法:const既可写在类型前,又可写在类型后。如上面的例子,常量指针:char const * ptr = “hello” 也是正确的。
    最后再举个例子,与迭代器经常在一起用。
    若希望迭代器所指向的东西不可变,则需要的是 const_iterator。例:

    std::vector<int>::const_iterator Iter = vec.begin();
    *Iter = 10;//错误,Iter是常量指针
    Iter++;//正确,Iter本身可变

    若希望迭代器本身不可变,指向的内容可变,则可以这样写:
    const std::vector<int>::iterator Iter = vec.begin();
    *Iter = 10//正确,指针常量
    Iter++;     //错误,指针本身不可变  

       指针常量定义时必须初始化,否则报编译错误,因为此时不赋值便没有机会赋值了.
         下面看几个简单的例子,可以说明他们的区别:
    第一个

     void main()
    {
    char *str1={"Hello"};
    char *str2={"Hello World"};
    char * const ptr1 =str1 ;
    //指针常量--指针本身是常量,指向的地址不可以变化,但是指向的地址所对应的内容可以变化

     ptr1 =str2; //错误 因为这是一个指针常量,改变指向的地址了

     printf("%c \n",*ptr1);
     }


     // 编译错误    error C3892: 'ptr1' : you cannot assign to a variable that is const    


    第二个

    void main()

    {
        char *str1={"Hello"};
        char *str2={"Hello World"};
         char * const ptr1 =str1 ;
         //指针常量--指针本身是常量,指向的地址不可以变化,但是指向的地址所对应的内容可以变化

         *ptr1 ='A';//错误,显示内存错误,因为“hello”为常量,不得修改,意即指针常量中,指针不得改,常量也不得改(#add)

    //   char *p = "abc";与
    //   const char* p = "abc";等价

    //如需要不出错,应该这样初始化 char str1[6] = "hello",即用数组,而不能用字符串常量


         printf("%c \n",*ptr1);
         }

    第三个

     void main()
    {
         char *str1={"Hello"};
        char *str2={"Hello World"};
         const char *ptr1 = str1;
         //常量指针--指向字符串常量,所指向的字符串内容不能变,但是指向的地址可以变化
           //相当于在此处将前边的str1 追加定义为常量
         ptr1=str2;// 正确 因为指向的地址是可以变化的

         printf("%s \n",ptr1);
         }
     
     //输出 Hello World

    第四个

     void main()
    {
         char *str1={"Hello"};
         char *str2={"Hello World"};
        const char *ptr1 = str2;
         //常量指针--指向字符串常量,所指向的字符串内容不能变,但是指向的地址可以变化
         
        ptr1='A';// 错误 因为指向的地址是内容是不可以变化的

         printf("%c /n",ptr1);
     }
    //编译错误    error C2440: '=' : cannot convert from 'char' to 'const char *' 

    相信从上面四个简单的例子可以看出他们不一样的地方把,在这里要请大家注意一下的地方是:

    指针常量的申明:const 放在* 和指针名之间 Type* const     pointer ;

    常量指针的申明:const放在类型说明符之前 const Type*     pointer ;

    实际分两部分: type* 为指针 const为常量  自由组合便成为指针常量,常量指针

                        (修正为 本质上看 * const两部分, *代表指针,const代表常量,)


    常量指针、指针常量判断原则const {int}* ,{int}* const,也就是const 和*先后顺序判断。

        const还可以修饰函数:

        如果给以指针传递方式的函数返回值加const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。例如函数
        const char * GetString(void);
        如下语句将出现编译错误:
        char *str = GetString();
        正确的用法是
        const char *str = GetString();
        如果函数返回值采用值传递方式,由于函数会把返回值复制到外部临时的存储单元中,加const 修饰没有任何价值。



    展开全文
  • 数组

    2019-09-26 19:04:04
    格式:类型说明符 数组名 [ 常量表达式 ] 例如:定义一个5个元素的整型数组 int array[5]; 1.int 表示定义的定义的数组是整型数组,即数组空间里面存放整形变量2.array 是定义数组的名称 3.[5] 是表示定义的...
  • 总结关于字符数组、字符串的知识,虽然这些东西都是很基础的内容,但是不少人还是经常会在这些问题上犯错。以下是个人的一些总结,没有什么高端的内容,仅仅希望提醒自己在这些细节上不要再犯错。
  • 数组公式是可对数组中的一个或多个项目执行多个计算的公式。你可以将数组视为值的一行或一列,或者视为值的行和列的组合。数组公式可以返回多个结果,也可以返回单个结果。从Office365的2018年9月更新开始,任何可...
  • 1[单选题] 下面关于“EOF”的叙述,正确的是A.EOF的值等于0B.EOF是在库函数文件中定义的符号常量C.文本文件和二进制文件都可以用EOF作为文件结束标志D.对于文本文件,fgetc函数读入最后一个字符时,返回值是EOF参考...
  • 判断题 1. 函数若无返回值,则它一定无形参。× 2. 在 C 程序中 , 函数既可以嵌套定义 , ... 以下能对二维数组a进行正确初始化的语句为( D )。 A.int a[2][]={{1},{4,5}}; B.int a[2][3]={1,2,3,4,5,6,7};
  • · PAGE 214· C语言程序设计之上机指导及同步训练第... 以下关于数组的描述正确的是(c )。A. 数组的大小是固定的,但可以有不同的类型的数组元素B. 数组的大小是可变的,但所有数组元素的类型必须相同C. 数组的大小...
  • 数组——数组概述

    2020-10-04 20:49:58
    数组——数组概述简单介绍一维数组的使用声明初始化数组元素的引用相关代码示例:数组元素的默认初始化值代码示例 简单介绍 数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号...
  • 讨论下面的问题前,我们先用sizeof()和strlen()测char数组长度: 当我们定义了一个这样一个数组: char str[10] = {‘h’,‘e’,‘l’,‘l’,‘o’}; 通过sizeof(str)我们可以求得str大小为10个字节(str内存分配空间...
  • 8.3通过指针引用数组8.3.1数组元素的指针一个变量有地址,一个数组包含若干个元素,每个数组元素都在内存中占用储存单元,它们都有相对应的地址。指针变量可以指向变量,也可以指向数组元素。数组元素的指针就是数组...
  • 考虑以下Java源文件Test.java(语法上不正确,但是用于说明预处理器的操作): aaaa // This represents code that should be copied without changing bbbb // Generate integer constants, with public ...
  • 数组结构体

    2013-08-16 19:12:10
    1、一般形式:类型说明符 数组名[常量表达式];例如: int a[10]; 元素为a[0]----a[9]. 2、常量表达式中不允许包含变量,可以包含常量或符号常量。 3、数组元素下标可以是任何整型常量、整型变量...
  • C语言数组

    千次阅读 2019-08-03 19:45:50
    超女选秀的第一组有5名超女,请提供一个界面,输入每位超女的体重,最后计算出超女的的平均体重。 用我们之前学习过的知识,程序示例如下: 示例(book41.c) ...数组有一个数组名,通过下标访问数组...
  • Cpp数组

    千次阅读 2019-01-18 18:51:29
    与 vector 类型相似,数组也可以保存某种类型的一组对象;...此常量表达式只能包含整型字面值常量、枚举常量或者用常量表达式初始化的整型 const 对象。非 const 变量以及要到运行阶段才知道其值的c...
  • 数组 数组简介

    2012-04-05 10:31:54
    不初始化数组,存储的是无用的数值,但是部分初始化数组,未初始化的元素则被设置为0 声明数组时可以不指定大小,让编译器自动匹配数组大小和初始化列表的项目数目。此时用sizeof来计算数组的大小。 #include<...
  • 数组总结

    2019-12-24 23:12:53
    一、数组 ⑴定义 数组就是一组相同类型的变量,它们往往都是为了表示同一批对象的统一属性。 数组可以是一维的,二维的或者多维的。 数组就是一个集合,里面存放了相同类型的数据元素 数组是计算机编程中的重要概念...
  • 指针数组&数组指针

    2017-01-24 17:07:52
    以下转自:指针数组数组指针二维数组: 1)定义形如int a[2][3],此时a代表的是这个二维数组的地址,sizeof(a)为24。 二级指针: 1)定义形如int **p:表示为指向指针的指针 2)二级指针不能和二维数组替换,如int ...
  • C语言数组考点归纳下面是百分网小编为大家收集的C语言数组考点归纳,欢迎借鉴学习!...(3)常量表达式表示数组元素的个数,即数组的长度,数组的下标从0开始,下标的最大值为:常量表达式-1;(4)常量表达...
  • C数组

    2020-04-17 09:42:04
    1 引言 ● 数组是由相同数据类型的相关联的数据...● 若要访问数组中某个特定的存储单元或数组元素,需要指定数组的名字以及该元素在数组中的位置号(即下标) ● 任何一个数组的第一个元素都是第0号元素,即位置号为0...
  • c语言数组

    2020-03-14 22:10:42
    a,b,c为数组名,表示内存首地址,是***地址常量*** 注:=左边不能为地址常量。 初始化 初始化方式:int a[4]={1,2,3,4}; 等价于:a[0]=1; a[1]=2; a[2]=3; a[3]=4; 注: (1)数据不初始化,其元素值...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 81,890
精华内容 32,756
关键字:

以下数组常量是正确的是