Rumah php教程 PHP开发 字符数组和字符指针

字符数组和字符指针

Dec 12, 2016 pm 05:16 PM
tatasusunan rentetan

问题1:

字符数组名可以作为左值吗?当然不行

比如 

char str[20] = {'h','e','l','l','o',' ','w','o','r','l','d'};

str++;

不可以这么干,因为字符数组名是一个常量指针,也就是是一个const char*

#include <stdio.h>

int main()
{
    char str[20] = {&#39;h&#39;,&#39;e&#39;,&#39;l&#39;,&#39;l&#39;,&#39;o&#39;,&#39; &#39;,&#39;w&#39;,&#39;o&#39;,&#39;r&#39;,&#39;l&#39;,&#39;d&#39;};
    printf("sizeof(str): %d\n",sizeof(str));
    printf("str: %s\n",str);
    str = str + 1;  //error
    return 0;
}
Salin selepas log masuk

运行结果如下:

字符串数组

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

#include <stdio.h>
#include <string.h>
int main(void)
{
    char buf[10];
    char *p= “afdal”;
    buf = p;  //将一个char* 赋给一个char[10],类型不一样,必然不成功
    printf(“the buf is:%s\n”,buf);
    return 0;
}
Salin selepas log masuk

问题2:

字符数组如何进行初始化?

#include <stdio.h>

int main()
{
    char ptr[20] = "hello world";  //success
    char str[20] = {&#39;h&#39;,&#39;e&#39;,&#39;l&#39;,&#39;l&#39;,&#39;o&#39;,&#39; &#39;,&#39;w&#39;,&#39;o&#39;,&#39;r&#39;,&#39;l&#39;,&#39;d&#39;};  //success
    char ctr[20];
    ctr = "hello world";  // error: incompatible types when assigning to type ‘char[20]’ from type ‘char *’
    return 0;
}
Salin selepas log masuk

在给字符数组初始化的时候,会自动在字符数组的结尾加上'\0'

#include <stdio.h>

int main()
{
    char str[20] = {&#39;h&#39;,&#39;e&#39;,&#39;l&#39;,&#39;l&#39;,&#39;o&#39;,&#39; &#39;,&#39;w&#39;,&#39;o&#39;,&#39;r&#39;,&#39;l&#39;,&#39;d&#39;};
    printf("sizeof(str): %d\n",sizeof(str));
    printf("str: %s\n",str);
    int i = 0;
    while(*(str + i) != &#39;\0&#39;)  //判断是否加上&#39;\0&#39;
    {
        printf("%c\n",*( str + i++));
    }
    return 0;
}
Salin selepas log masuk

运行结果如下:

字符串数组

问题3:

字符数组越界访问能编译通过吗?

字符数组越界访问编译可以通过,没有报错,这样会出现很多的问题

#include <stdio.h>

int main()
{
    char str[12] = {&#39;h&#39;,&#39;e&#39;,&#39;l&#39;,&#39;l&#39;,&#39;o&#39;,&#39; &#39;,&#39;w&#39;,&#39;o&#39;,&#39;r&#39;,&#39;l&#39;,&#39;d&#39;};
    printf("%c\n",str[100]);
    return 0;
}
Salin selepas log masuk

字符串数组

打印为空

问题4:

字符数组和字符指针又有什么区别呢?

首先在内存的中位置不同,字符数组保存的字符串存放在内存的栈中,而字符指针指向的字符串保存在内存的静态存储区中。

其次字符数组保存的字符串属于字符串变量,可以被修改,而字符指针指向的字符串是属于字符串常量,不能被修改。

#include <stdio.h>

int main()
{
    char str[12] = {&#39;h&#39;,&#39;e&#39;,&#39;l&#39;,&#39;l&#39;,&#39;o&#39;,&#39; &#39;,&#39;w&#39;,&#39;o&#39;,&#39;r&#39;,&#39;l&#39;,&#39;d&#39;};
    char* ptr = "hello world";
    str[0] = &#39;f&#39;;
    ptr[0] = &#39;f&#39;;  //将字符指针指向的字符串修改,将出现段错误,因为该内存地址只读,因为该字符串属于常量
    return 0;
}
Salin selepas log masuk

运行结果:

字符串数组

段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址、访问了系统保护的内存地址、访问了只读的内存地址等等情况。

#include <stdio.h>

int main()
{
    char* ptr = "hello world";
    ptr[11] = &#39;!&#39;;  //往常量字符串末尾添加字符,相当于连接两个字符串,出错
    ptr[12] = &#39;\0&#39;;
    return 0;
}
Salin selepas log masuk

这样也会出现段错误。

问题5:

字符指针是不是和字符数组名都是指针常量呢?

不是,字符指针,可以改变它的指向,也就是可以为左值。可以将一个字符指针指向一个字符串常量后又指向另外一个字符串常量。字符指针在为初始化之前,他是一个未定义的值,将指向任何可能的地方,所以在使用字符指针时一定要注意初始化。

#include <stdio.h>

int main()
{
    char* ptr;
    printf("ptr: %c\n",*ptr);
    return 0;
}
Salin selepas log masuk

运行结果:

编译可以通过,但是ptr指向的内存地址是任意的

当然也可以将一个字符指针指向一个字符数组。

#include <stdio.h>

int main()
{
    char str[12] = {&#39;h&#39;,&#39;e&#39;,&#39;l&#39;,&#39;l&#39;,&#39;o&#39;,&#39; &#39;,&#39;w&#39;,&#39;o&#39;,&#39;r&#39;,&#39;l&#39;,&#39;d&#39;};
    char* ptr = str;
    printf("ptr: %s\n",ptr);
    return 0;
}
Salin selepas log masuk

运行结果:

字符串数组

问题6:

如果一个字符指针指向一个堆中动态内存。那么我们如何初始化该内存中的值?

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
    char* str = (char*)malloc(sizeof(char)*20);
    printf("str:%p\n",str);     //str在堆中内存首地址
    str = "hello world";
    printf("str:%p\n",str);    //str在静态存储区内存首地址
    char* ptr = "I love you";
    printf("ptr:%p\n",ptr);    //str在静态存储区内存首地址
    return 0;
}
Salin selepas log masuk

运行结果如下:

字符串数组

很明显前后的地址不一样,前一个指向堆中的内存的地址,而后一个指向了静态存储区中的内存的地址。我本以为我通过上述方式进行初始化str的时候,我可以将堆中内存进行初始化,我发现我错了,字符指针将被重新指向。但是我想如果我们将str声明为const呢?那将会出现什么样的结果呢?

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
    const char* str = (char*)malloc(sizeof(char)*20);  //我以为const将修饰str,使得str不能再作为左值而出现,我错了,const修饰的是由str指向的字符串,
    printf("str:%p\n",str);                            //该字符串不能再被修改
    str = "hello world";
    printf("str:%p\n",str);  
    return 0;
}
Salin selepas log masuk

运行结果:

字符串数组

如果我们将上述的代码做如下修改,程序还能编译通过吗?

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
    const char* str = (char*)malloc(sizeof(char)*20);
    printf("str:%p\n",str);
    str[0] = &#39;h&#39;;    //这种赋值才是对str原来所指向的堆中的内存的赋值,编译不过,因为str指向的堆中的内存是只读的。
    str = "hello world";     
    printf("str:%p\n",str);
    return 0;
}
Salin selepas log masuk

运行结果如下:

字符串数组

上述就引发了我思考为什么const修饰的是str指向的字符串,而不是str本身呢?

原来,char* const str才是真正的修饰str本身,使得str为只读的,不能再被修改,也就是重新指向其他内存地址。而const char* str 和 char const* str 的意义是一致的,都是修饰的是*str。

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
    char* const str = (char*)malloc(sizeof(char)*20);
    printf("str:%p\n",str);
    str[0] = &#39;h&#39;; 
    str = "hello world";      //变量str被重新指向,error,编译不过
    printf("str:%p\n",str);
    return 0;
}
Salin selepas log masuk

运行结果如下:

字符串数组

那么我们又该如何初始化一个字符指针指向的内存呢?

其实我们可以很清楚的分析,如果str是一个字符指针,也就是一个变量,变量是可以被重新赋值的,而每一个字符串本身是有一个地址的,str = “hello world”,必然就是改变了str的值,使得str保存着"hello world"的内存首地址,而一旦你将str = "I love you",必然str将保存这"I love you"的内存首地址,这都是毋庸置疑的。

#include <stdio.h>

int main()
{
    printf("hello world:%p\n","hello world");   //将打印出"hello world"的内存地址
    printf("I love you:%p\n","I love you");    //将打印出"I love you"的内存地址
    return 0; 
}
Salin selepas log masuk

运行如下:

字符串数组

下面我得回到这样一个问题?

str 和 *str的区别,很明显,str是一个指针,而*str是str指向的内存的存放的值,既然我们想改变str指向内存中的值,既*str的值,那么为何不将*str作为左值,来初始化str所指向内存的值呢?而*str 不就是 str[0]吗?所以很明显了。上述问题:那么我们又该如何初始化一个字符指针指向的内存呢?当然这个仅限于字符指针指向的是由mlloc分配的堆中的内存以及字符数组指向的栈中的内存。而字符指针如果指向字符常量,不可修改字符指针指向的内存的值,因为字符常量是只读的。

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
    char* const str = (char*)malloc(sizeof(char)*20);
    printf("str:%p\n",str);
    str[0] = &#39;A&#39;;     //数组下标型赋值
    *(str + 1) = &#39;l&#39;;  //指针++型赋值
    str[2] = &#39;e&#39;,
    *(str + 3) = &#39;x&#39;;
    printf("str:%s\n",str);  
    printf("str:%p\n",str);
    return 0;
}
Salin selepas log masuk

运行如下:

字符串数组

#include <stdio.h>
#include <stdlib.h>
int main()
{ 
    char str[20]; 
    printf("str:%p\n",str);
    str[0] = &#39;A&#39;; 
    *(str + 1) = &#39;l&#39;;
    str[2] = &#39;e&#39;,
    *(str + 3) = &#39;x&#39;;
    //str[4] = &#39;\0&#39;;  //当我们没有手动给字符串结尾附上&#39;\0&#39;
    printf("str:%s\n",str);
    printf("str:%p\n",str);
    return 0; 
}
Salin selepas log masuk

运行如下:

字符串数组

上述的运行结果说明上述程序并没有自动给字符串结尾附上'\0',对于字符数组除非这样赋值,str[20] = "hello world",不然你就得手动给字符串附上字符串结尾'\0'。

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
    char str[20]; 
    printf("str:%p\n",str);
    str[0] = &#39;A&#39;; 
    *(str + 1) = &#39;l&#39;;
    str[2] = &#39;e&#39;,
    *(str + 3) = &#39;x&#39;;
    str[4] = &#39;\0&#39;;
    printf("str:%s\n",str);
    printf("str:%p\n",str);
    return 0; 
}   
~
Salin selepas log masuk

运行结果:

字符串数组

附上一段我关于memcpy()和memmove()的代码的实现。

#include <stdio.h>
#include <stdlib.h>

void mem_copy(char* const dest, const char* const src)
{
    for(int i = 0; *(src + i) != &#39;\0&#39;; i++)
        *(dest + i) = *(src + i);
}

void mem_move(char* const dest, const char* const src)
{
    int i = 0;
    while(*(src + i) != &#39;\0&#39;)
        i++;
    for(; i != -1; i--)
        *(dest + i) = *(src + i);
}

int main()
{
    char* src = "hello world";
    char* const dest1 = (char*)malloc(sizeof(char) * 20);
    char dest2[20];
    mem_copy(dest1,src);
    mem_move(dest2,src);
    printf("dest1:%s\n",dest1);
    printf("dest2:%s\n",dest2);
    return 0;
}
Salin selepas log masuk

当我们需要将内存的中的某一地址段的内容拷贝到内存中另一地址段中,以上是将字符串常量区的内容拷贝到堆中和栈中,我们可以看到我分别使用了malloc和字符数组,当然我们得考虑可能在拷贝的过程中会有地址段重叠的问题,重叠该怎么拷贝,解决方案很简单,就是从尾向前拷贝,即可。

运行结果如下:

字符串数组

以上是我对c语言中字符串操作的一些理解

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Arahan sembang dan cara menggunakannya
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Cara menggunakan fungsi split() dalam oracle Cara menggunakan fungsi split() dalam oracle May 07, 2024 pm 01:06 PM

Fungsi SPLIT() membahagikan rentetan kepada tatasusunan dengan pembatas yang ditentukan, mengembalikan tatasusunan rentetan di mana setiap elemen ialah bahagian yang dipisahkan pembatas bagi rentetan asal. Penggunaan termasuk: membahagikan senarai nilai yang dipisahkan koma kepada tatasusunan, mengekstrak nama fail daripada laluan, dan membahagikan alamat e-mel kepada nama pengguna dan domain.

Bagaimana untuk mengisih rentetan dalam java Bagaimana untuk mengisih rentetan dalam java Apr 02, 2024 am 02:18 AM

Cara untuk mengisih rentetan dalam Java: Gunakan kaedah Arrays.sort() untuk mengisih tatasusunan rentetan dalam tertib menaik. Gunakan kaedah Collections.sort() untuk mengisih senarai rentetan dalam tertib menaik. Gunakan antara muka Pembanding untuk menyusun rentetan tersuai.

Apakah maksud \0 dalam bahasa c Apakah maksud \0 dalam bahasa c Apr 27, 2024 pm 10:54 PM

Dalam bahasa C, \0 ialah tanda akhir rentetan, dipanggil aksara nol atau penamat. Memandangkan rentetan disimpan dalam ingatan sebagai tatasusunan bait, pengkompil mengecam penghujung rentetan melalui \0, memastikan rentetan dikendalikan dengan betul. \0 Cara ia berfungsi: Pengkompil berhenti membaca aksara apabila ia menemui \0 dan aksara seterusnya diabaikan. \0 sendiri tidak menduduki ruang storan. Faedah termasuk pengendalian rentetan yang boleh dipercayai, kecekapan yang dipertingkatkan (tidak perlu mengimbas keseluruhan tatasusunan untuk mencari penghujungnya), dan kemudahan perbandingan dan manipulasi.

Apakah maksud args dalam java Apakah maksud args dalam java Apr 25, 2024 pm 10:15 PM

args bermaksud argumen baris arahan dalam Java dan merupakan tatasusunan rentetan yang mengandungi senarai argumen yang dihantar kepada program apabila ia dimulakan. Ia hanya tersedia dalam kaedah utama, dan nilai lalainya ialah tatasusunan kosong, dengan setiap parameter boleh diakses oleh indeks. args digunakan untuk menerima dan memproses argumen baris arahan untuk mengkonfigurasi atau menyediakan data input apabila program bermula.

Apakah maksud args dalam java Apakah maksud args dalam java May 07, 2024 am 02:24 AM

args ialah tatasusunan parameter khas kaedah utama dalam Java, digunakan untuk mendapatkan tatasusunan rentetan parameter baris arahan atau input luaran. Dengan mengakses tatasusunan args, atur cara boleh membaca hujah ini dan memprosesnya mengikut keperluan.

Aplikasi teknologi kecerdasan buatan dalam fungsi PHP Aplikasi teknologi kecerdasan buatan dalam fungsi PHP May 01, 2024 pm 01:15 PM

Teknologi AI telah digabungkan dengan fungsi PHP untuk meningkatkan kefungsian aplikasi. Aplikasi AI khusus termasuk: menggunakan algoritma pembelajaran mesin untuk mengklasifikasikan teks, seperti Naive Bayes. Lakukan analisis teks yang mendalam menggunakan teknik pemprosesan bahasa semula jadi seperti pembahagian perkataan dan pembubuhan.

Bagaimana untuk mengisih aksara Cina dalam persekitaran bahasa C? Bagaimana untuk mengisih aksara Cina dalam persekitaran bahasa C? Feb 18, 2024 pm 02:10 PM

Bagaimana untuk melaksanakan fungsi pengisihan aksara Cina dalam perisian pengaturcaraan bahasa C? Dalam masyarakat moden, fungsi pengisihan aksara Cina adalah salah satu fungsi penting dalam banyak perisian. Sama ada dalam perisian pemprosesan perkataan, enjin carian atau sistem pangkalan data, aksara Cina perlu diisih untuk memaparkan dan memproses data teks Cina dengan lebih baik. Dalam pengaturcaraan bahasa C, bagaimana untuk melaksanakan fungsi pengisihan aksara Cina? Satu kaedah diperkenalkan secara ringkas di bawah. Pertama sekali, untuk melaksanakan fungsi pengisihan aksara Cina dalam bahasa C, kita perlu menggunakan fungsi perbandingan rentetan. Berlari

Apakah kesan fungsi C++ terhadap prestasi program? Apakah kesan fungsi C++ terhadap prestasi program? Apr 12, 2024 am 09:39 AM

Kesan fungsi pada prestasi program C++ termasuk overhed panggilan fungsi, pembolehubah tempatan dan overhed peruntukan objek: Overhed panggilan fungsi: termasuk peruntukan bingkai tindanan, pemindahan parameter dan pemindahan kawalan, yang mempunyai kesan ketara pada fungsi kecil. Overhed pembolehubah tempatan dan peruntukan objek: Sebilangan besar pembolehubah tempatan atau penciptaan objek dan pemusnahan boleh menyebabkan limpahan tindanan dan kemerosotan prestasi.

See all articles