Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C:字符指针和数组之间的差异_C_Arrays_Pointers - Fatal编程技术网

C:字符指针和数组之间的差异

C:字符指针和数组之间的差异,c,arrays,pointers,C,Arrays,Pointers,考虑: char amessage[] = "now is the time"; char *pmessage = "now is the time"; 我从第二版中读到,上述两种说法并不相同 我一直认为数组是一种方便的方法来操作指针来存储一些数据,但事实显然并非如此。。。在C语言中,数组和指针之间的“非平凡”区别是什么?没错,但这是一个细微的区别。基本上,前者: char amessage[] = "now is the time"; 定义其成员位于当前作用域堆栈空间中的数组,而: cha

考虑:

char amessage[] = "now is the time";
char *pmessage = "now is the time";
我从第二版中读到,上述两种说法并不相同


我一直认为数组是一种方便的方法来操作指针来存储一些数据,但事实显然并非如此。。。在C语言中,数组和指针之间的“非平凡”区别是什么?

没错,但这是一个细微的区别。基本上,前者:

char amessage[] = "now is the time";
定义其成员位于当前作用域堆栈空间中的数组,而:

char *pmessage = "now is the time";
定义一个指针,该指针位于当前作用域的堆栈空间中,但引用其他位置的内存(在本例中,“now is the time”存储在内存的其他位置,通常是字符串表)

另外,请注意,由于属于第二个定义(显式指针)的数据未存储在当前作用域的堆栈空间中,因此未指定其确切存储位置,因此不应修改


编辑:正如Mark、GMan和Pavel所指出的,当操作符的地址用于这些变量中的任何一个时,也存在差异。例如,&pmessage返回char**类型的指针,或指向chars的指针,而&amessage返回char(*)[16]类型的指针,或指向16个字符的数组的指针(与char**一样,需要在litb指出时取消引用两次)

数组包含元素。一个指针指向它们

第一种是简短的说法

char amessage[16];
amessage[0] = 'n';
amessage[1] = 'o';
...
amessage[15] = '\0';
也就是说,它是一个包含所有字符的数组。特殊初始化为您初始化它,并自动确定其大小。数组元素是可修改的-您可以覆盖其中的字符

第二种形式是指针,它只指向字符。它不直接存储字符。由于数组是字符串文字,因此不能使用指针并写入它所指向的位置

char *pmessage = "now is the time";
*pmessage = 'p'; /* undefined behavior! */

此代码可能会在您的计算机上崩溃。但它可以做任何它喜欢的事情,因为它的行为是不确定的

第二个在ELF的某个只读部分分配字符串。 请尝试以下操作:

#include <stdio.h>

int main(char argc, char** argv) {
    char amessage[] = "now is the time";
    char *pmessage = "now is the time";

    amessage[3] = 'S';
    printf("%s\n",amessage);

    pmessage[3] = 'S';
    printf("%s\n",pmessage);
}
#包括
int main(字符argc,字符**argv){
char amessage[]=“现在是时候了”;
char*pmessage=“现在是时候了”;
a消息[3]=“S”;
printf(“%s\n”,一条消息);
pmessage[3]=“S”;
printf(“%s\n”,pmessage);
}

在第二次赋值(pmessage[3]='S')时,您将得到一个segfault。与分配在两个不同位置的字符串“now is the time”的内存一起,您还应该记住,数组名充当指针值,而pmessage是指针变量。主要区别在于指针变量可以修改为指向其他地方,而数组不能

char arr[] = "now is the time";
char *pchar = "later is the time";

char arr2[] = "Another String";

pchar = arr2; //Ok, pchar now points at "Another String"

arr = arr2; //Compiler Error! The array name can be used as a pointer VALUE
            //not a pointer VARIABLE

数组是常量指针。不能更新其值并使其指向其他任何位置。
对于指针,您可以这样做。

我不能有效地添加到其他答案中,但我要指出,在中,Peter van der Linden详细介绍了这个示例。如果你问这些问题,我想你会喜欢这本书的



另外,您可以为
pmessage
指定一个新值。不能将新值分配给
amessage
;它是不可变的。

如果数组的定义使其大小在声明时可用,
sizeof(p)/sizeof(数组类型)
将返回数组中的元素数。

第一种形式(
amessage
)定义了一个包含字符串副本的变量(数组)
“现在是时间”

第二种形式(
pmessage
)定义了一个变量(指针),该变量位于与字符串的任何副本不同的位置
“现在是时间”

请尝试以下程序:

#include <inttypes.h>
#include <stdio.h>

int main (int argc, char *argv [])
{
     char  amessage [] = "now is the time";
     char *pmessage    = "now is the time";

     printf("&amessage   : %#016"PRIxPTR"\n", (uintptr_t)&amessage);
     printf("&amessage[0]: %#016"PRIxPTR"\n", (uintptr_t)&amessage[0]);
     printf("&pmessage   : %#016"PRIxPTR"\n", (uintptr_t)&pmessage);
     printf("&pmessage[0]: %#016"PRIxPTR"\n", (uintptr_t)&pmessage[0]);

     printf("&\"now is the time\": %#016"PRIxPTR"\n",
            (uintptr_t)&"now is the time");

     return 0;
}
#包括
#包括
int main(int argc,char*argv[])
{
char amessage[]=“现在是时候了”;
char*pmessage=“现在是时候了”;
printf(“&amessage:%#016”PRIxPTR“\n”,(uintpttr\u t)&amessage);
printf(“&amessage[0]:%#016“PRIxPTR”\n”,(uintptpr\u t)和amessage[0]);
printf(“&pmessage:%#016“PRIxPTR”\n”,(uintpttr\u t)&pmessage);
printf(“&pmessage[0]:%#016“PRIxPTR”\n”,(uintptpr\u t)&pmessage[0]);
printf(&“现在是时间”:%#016“PRIxPTR”\n,
(uintpttr__t)和"现在是时候";;
返回0;
}
您将看到,虽然
&amessage
等于
&amessage[0]
,但对于
&pmessage
&pmessage[0]
,情况并非如此。事实上,您将看到存储在
amessage
中的字符串位于堆栈上,而
pmessage
指向的字符串位于其他位置

最后一个printf显示字符串文本的地址。如果您的编译器执行“字符串池”,那么字符串“now is time”(现在是时间)将只有一个副本,您将看到它的地址与
amessage
的地址不同。这是因为
amessage
在初始化字符串时获取该字符串的副本

最后,要点是
amessage
将字符串存储在它自己的内存中(在本例中,在堆栈上),而
pmessage
指向存储在别处的字符串。

对于此行: char amessage[]=“现在是时候了”

编译器将评估amessage的使用情况,将其作为指向包含字符“now is time”的数组开始的指针。编译器为“now is The time”分配内存,并使用字符串“now is The time”对其进行初始化。您知道该消息存储在哪里,因为消息总是指该消息的开头。消息可能不会被赋予新值-它不是变量,而是字符串“now is the time”的名称

这一行: char*pmessage=“现在是时候了”

声明一个变量pmessage,该变量已初始化(给定初始值)字符串“now is the time”的起始地址。与amessage不同,pmessage可以被赋予一个新值。在这种情况下,就像在previ中一样
                0x00  0x01  0x02  0x03  0x04  0x05  0x06  0x07
    0x00008000:  'n'   'o'   'w'   ' '   'i'   's'   ' '   't'
    0x00008008:  'h'   'e'   ' '   't'   'i'   'm'   'e'  '\0'
        ...
amessage:
    0x00500000:  'n'   'o'   'w'   ' '   'i'   's'   ' '   't'
    0x00500008:  'h'   'e'   ' '   't'   'i'   'm'   'e'  '\0'
pmessage:
    0x00500010:  0x00  0x00  0x80  0x00
char amessage[] = "now is the time";
strcpy(amessage, "the time is now");
char *pmessage = "now is the time";
strcpy(amessage, pmessage); /* OKAY */
strcpy(pmessage, amessage); /* NOT OKAY */
strtok(amessage, " ");      /* OKAY */
strtok(pmessage, " ");      /* NOT OKAY */
scanf("%15s", amessage);      /* OKAY */
scanf("%15s", pmessage);      /* NOT OKAY */
pmessage = amessage;
//ATTENTION:
    //Pointer depth 1
     int    marr[]  =  {1,13,25,37,45,56};      // array is implemented as a Pointer TO THE FIRST ARRAY ELEMENT
     int*   pmarr   =  marr;                    // don't use & for assignment, because same pointer depth. Assigning Pointer = Pointer makes them equal. So pmarr points to the first ArrayElement.

     int*   point   = (marr + 1);               // ATTENTION: moves the array-pointer in memory, but by sizeof(TYPE) and not by 1 byte. The steps are equal to the type of the array-elements (here sizeof(int))

    //Pointer depth 2
     int**  ppmarr  = &pmarr;                   // use & because going one level deeper. So use the address of the pointer.

//TYPES
    //array and pointer are different, which can be seen by checking their types
    std::cout << "type of  marr is: "       << typeid(marr).name()          << std::endl;   // int*         so marr  gives a pointer to the first array element
    std::cout << "type of &marr is: "       << typeid(&marr).name()         << std::endl;   // int (*)[6]   so &marr gives a pointer to the whole array

    std::cout << "type of  pmarr is: "      << typeid(pmarr).name()         << std::endl;   // int*         so pmarr  gives a pointer to the first array element
    std::cout << "type of &pmarr is: "      << typeid(&pmarr).name()        << std::endl;   // int**        so &pmarr gives a pointer to to pointer to the first array elelemt. Because & gets us one level deeper.
#include <stdio.h>

int main ()
{

char amessage[] = "now is the time"; /* Attention you have created a "string literal" */

char *pmessage = "now is the time";  /* You are REUSING the string literal */


/* About arrays and pointers */

pmessage = NULL; /* All right */
amessage = NULL; /* Compilation ERROR!! */

printf ("%d\n", sizeof (amessage)); /* Size of the string literal*/
printf ("%d\n", sizeof (pmessage)); /* Size of pmessage is platform dependent - size of memory bus (1,2,4,8 bytes)*/

printf ("%p, %p\n", pmessage, &pmessage);  /* These values are different !! */
printf ("%p, %p\n", amessage, &amessage);  /* These values are THE SAME!!. There is no sense in retrieving "&amessage" */


/* About string literals */

if (pmessage == amessage)
{
   printf ("A string literal is defined only once. You are sharing space");

   /* Demostration */
   "now is the time"[0] = 'W';
   printf ("You have modified both!! %s == %s \n", amessage, pmessage);
}


/* Hope it was useful*/
return 0;
}
char c[] = "abc";      
char c[] = {'a', 'b', 'c', '\0'};
char *c = "abc";
/* __unnamed is magic because modifying it gives UB. */
static char __unnamed[] = "abc";
char *c = __unnamed;
char s[] = "abc", t[3] = "abc";
char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };
char *p = "abc";
#include <stdio.h>

int main(void) {
    char *s = "abc";
    printf("%s\n", s);
    return 0;
}
gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o
 char *s = "abc";
8:  48 c7 45 f8 00 00 00    movq   $0x0,-0x8(%rbp)
f:  00 
        c: R_X86_64_32S .rodata
 char s[] = "abc";
17:   c7 45 f0 61 62 63 00    movl   $0x636261,-0x10(%rbp)
readelf -l a.out
 Section to Segment mapping:
  Segment Sections...
   02     .text .rodata