导图社区 C语言字符指针
C语言是一门面向过程、抽象化的通用程序设计语言,广泛应用于底层开发。C语言能以简易的方式编译、处理低级存储器。
编辑于2021-07-30 22:14:40C语言字符指针
字符串的引用方式
在 C 程序中,字符串是存放在字符数组中的
字符串的引用方法
用字符数组存放一个字符串,可以通过数组名和下标引用字符串中一个字符,也可以通过数组名和格式声明 “%s” 输出该字符。
用字符指针变量指向一个字符串常量,通过字符指针变量引用字符串常量。
示例
题目:定义一个字符数组,在其中存放字符串 “I love Shiyanlou!”,输出该字符串和第 10 个字符。
代码实现
#include<stdio.h> int main() { char string[] = "I love you yuan qiu xia!"; printf("%s\n", string); printf("%c\n", string[9]); return 0; }
代码解析
在定义字符数组 string 时未指定长度,由于对它初始化,因此它的长度是确定的,长度应为 18,其中 17 个字节存放 “I love Shiyanlou!” 这 17 个字符(包含空格和感叹号),最后一个字节存放字符串 '\0',数组名 string 代表字数组首元素的地址。
示例
代码实现
#include<stdio.h> int main() { char *string = "I love u yuan qiu xia!"; char *p; char *i; p = string; printf("%s\n", string); for(i=p; *i!='\0'; i++) { printf("%c\t", *i); } printf("%c\n", *(p+2)); }
程序分析
对字符指针变量 string 初始化,实际上是把字符串第一个元素的地址赋给指针变量 string,使 string 指向字符串的第一个字符。 有人误认为 string 是一个字符串变量,以为在定义时把 “I love Shiyanlou!” 这几个字符赋给该字符串变量,这是不对的。在 C 语言中只有字符变量,没有字符串变量。
以下语句 printf("%s\n",string);中 %s 是输出字符串时所用的格式,在输出项中给出字符指针变量名 string,则系统会输出 string 所指向的字符串第一个字符,然后自动使 string 加 1,使之指向下一个字符,再输出该字符...如此直到遇到字符串结束标志 '\0',因此再输出是能确定输出的字符到何时结束。
综合示例
题目:将字符串 a 复制为字符串 b,然后输出字符串 b。
解题思路
定义两个字符数组 a 和 b,用 “I am a programmer” 对 a 数组进行初始化。将 a 数组中的字符逐个复制到 b 数组中。可以用不同的方法引用并输出字符数组元素,我们本例采用地址出各元素的值。通过改变指针变量的值使它指向字符串中的不同字符。
代码实现
#include<stdio.h> int main() { char a[] = "I am a programmer"; char b[22]; int i; for(i=0; *(a + i)!='\0'; i++) { *(b + i) = *(a + i); } *(b + i) = '\0'; printf("string a is: %s\n", a); printf("string b is: "); for(i=0; b[i]!='\0'; i++) { printf("%c", b[i]); } printf("\n"); return 0; }
#include<stdio.h> int main() { char a[] = "I am a programmer!"; char b[22]; char *p1; char *p2; p1 = a; p2 = b; for(; * p1!='\0'; p1++, p2++) { * p2 = * p1; } * p2 = '\0'; printf("string a is : %s\n", a); printf("string b is : %s\n", b); return 0; }
字符指针作函数参数
假如想把一个字符串从一个函数“传递”到另一个函数,可以用地址传递的办法,即用字符数组名作参数,也可以用字符指针变量做参数。在被调用的函数中可以改变字符串的内容,在主调函数中可以引用改变后的字符串。在函数调用实现字符串的复制。
示例
定义一个函数 copy_string 用来实现字符串复制的功能,在主函数中调用此函数,函数的形参和实参可以分别用字符数组名或字符指针变量。分别编程,以供分析比较。
代码实现
#include<stdio.h> int main() { void copy_string(char from[], char to[]); char a[] = "I love you"; char b[] = "yuan qiu xia!"; printf("The string a is: %s\n. string b is: %s\n", a, b); printf("copy string a to b is: "); copy_string(a, b); printf("\nstring a=%s\nstring b=%s\n", a, b); return 0; } void copy_string(char from[], char to[]) { int i = 0; while(from[i]!='\0') { to[i] = from[i]; i++; } to[i] = '\0'; }
#include<stdio.h> int main() { void copy_string(char *from, char *to); char *a = "I love you"; // char *b = "yuan qiu xia!"; char b[] = "yuan qiu xia!"; printf("string a=%s\nstring b=%s\n",a, b); printf("copy string a to string b:\n"); copy_string(a, b); printf("\n string a=%s\n string b=%s\n",a, b); return 0; } void copy_string(char *from, char *to){ while(*from!='\0') { *to++ = *from++; } *to = '\0'; // for(; *from!='\0'; from++, to++) // { // *to = * from; // } // *to = '\0'; }
#include<stdio.h> int main() { void copy_string(char from[], char to[]); char a[] = "I love you"; char b[] = "yuan qiu xia!"; char *from; char * to; from = a; to = b; printf("string a=%s\nstring b=%s\n",a,b); printf("copy string a to string b:\n"); copy_string(from,to); printf("\n string a=%s\n string b=%s\n",a,b); return 0; } void copy_string(char from[],char to[]){ int i = 0; while(from[i]!='\0') { to[i] = from[i]; i++; } to[i] = '\0'; }
#include<stdio.h> int main() { void copy_string(char *from, char *to); char *a = "I love you"; char b[] = "yuan qiu xia!"; char *p = b; printf("string a=%s\nstring b=%s\n",a, b); printf("copy string a to string b:\n"); copy_string(a, p); printf("\n string a=%s\n string b=%s\n",a, b); return 0; } void copy_string(char *from, char *to){ while(*from!='\0') { *to++ = *from++; } *to = '\0'; }
代码分析
将数组 a 复制到数组 b 后,未能全部覆盖 b 数组原有内容。b 数组最后 3 个元素仍保留原状。在输出 b 时由于按 %s 输出,遇到 '\0' 就会结束,因此第一个 '\0' 后的字符不输出。
我们使用长度改写以下
#include<stdio.h> #include<string.h> int main(){ void copy_string(char from[],char to[], int x, int y); char a[] = "I am a teacher"; char b[] = "You are a programmer"; char *from = a,*to = b; int len_a = strlen(a); int len_b = strlen(b); printf("len_a is : %d\n, len_b is :%d\n", len_a, len_b); printf("string a=%s\nstring b=%s\n",a,b); printf("copy string a to string b:\n"); copy_string(from, to, len_a, len_b); printf("\n string a=%s\n string b=%s\n",a,b); return 0; } void copy_string(char from[], char to[], int x, int y) { int i = 0; while(from[i]!='\0') { to[i] = from[i]; i++; } if(x > y) { to[i] = '\0'; } }
string a=I am a teacher string b=I am a teacherrammer
copy_string 不变,在 main 函数中定义字符指针变量 from 和 to,分别指向两个字符数组 a 和 b。 指针变量 from 的值是 a 数组首元素的地址,指针变量 to 的值是 b 数组首元素的地址。它们作为实参,把 a 数组首元素的地址和 b 数组首元素的地址传递给形参数组名 from 和 to(它们实质也是指针变量)
形参改用 char * 型变量(即字符指针变量)。在程序(1)和(2)中 copy_string 函数的参数用字符数组名,其实编译系统是把字符数组名按指针变量处理的,只是表示形式不同。
这样写为什么报错
#include<stdio.h> int main() { void copy_string(char *from, char *to); char *a = "I love you"; char *b = "yuan qiu xia!"; char *p = b; printf("string a=%s\nstring b=%s\n",a, b); printf("copy string a to string b:\n"); copy_string(a, p); printf("\n string a=%s\n string b=%s\n",a, b); return 0; } void copy_string(char *from, char *to){ while(*from!='\0') { *to++ = *from++; } *to = '\0'; }
有!它们最根本的区别是在内存中的存储区域不一样,字符数组存储在全局数据区或栈区,第二种形式的字符串存储在常量区。全局数据区和栈区的字符串(也包括其他数据)有读取和写入的权限,而常量区的字符串(也包括其他数据)只有读取权限,没有写入权限。
使用字符指针变量和字符数组的比较
区别对待
char *str = "http://c.biancheng.net";
char str[] = "http://c.biancheng.net";
相同点
这一切看起来和字符数组是多么地相似,它们都可以使用%s输出整个字符串,都可以使用*或[ ]获取单个字符
不同点
有!它们最根本的区别是在内存中的存储区域不一样,字符数组存储在全局数据区或栈区,第二种形式的字符串存储在常量区。全局数据区和栈区的字符串(也包括其他数据)有读取和写入的权限,而常量区的字符串(也包括其他数据)只有读取权限,没有写入权限。
总结归纳
字符数组由若干元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第 1 个字符的地址),绝不是将字符串放到字符指针变量中。
赋值方式。可以使用字符串对字符指针变量赋值,但不能对数组名赋值。
char *a; a = "I love shiyanlou!"; //将字符串首元素地址赋给指针变量,合法。但是赋给a的不是字符串,只是一个字符串首元素的地址。
√
char str[14]; str[0] = 'I'; //合法,对字符数组元素赋值 str = "I love Shiyanou"; //非法,数组名是地址,是常量,不能被赋值
存储单元的内容。编译时为字符数组分配若干存储单元,以存放各元素的值,而对字符指针变量,只分配一个存储单元。
指针总结
首先要准确地弄清楚指针的含义。指针就是地址,凡是出现“指针”的地方,都可以用“地址”代替,例如,变量的指针就是变量的地址,指针变量就是地址变量。 要区别指针和指针变量。指针就是地址本身,例如 2008 是某一变量的地址,2008 就是变量的指针。而指针变量是用来存放地址的变量。
什么叫指向?地址就意味着指向,因为通过地址能找到具有该地址的对象。对于指针变量来说,把谁的地址存放在指针变量中,就说此指针变量指向谁。但应该注意:并不是任何类型的数据都可以存放在同一个指针变量中的。
int a,*p; float b; p = &a; //a 是 int 类型,合法 p = &b; //b 是 float 类型,类型不匹配
指针变量加(减)一个整数。例如:p++,p- -,p+i,p-i,p-=i 等均是指针变量加减一个整数。将该指针变量的原值(地址)和它指向的变量所占用的存储单元的字节数相加(减)。
指针变量赋值。将一个变量地址赋给一个指针变量
p = &a; //将变量 a 的地址赋给 p p = &array; //将数组 array 的地址赋给 p(这里 p 指向整个数组,这个地址的值和数组首元素的值实际上是相同的,但意义是不同的,你可以尝试打印出(&array + 1)和(array + 1)的值来看看) p = array; //将数组 array 的首元素的地址赋给 p p = &a[0]; //将数组 array 的首元素的地址赋给 p p = &array[i]; //将数组 array 的第 i 个元素的地址赋给 p p = max; //max 为已定义的函数,将 max 的入口地址赋给 p p1 = p2; //p1 和 p2 是基类型相同指针变量,将 p2 的值赋给 p1
使用优势
提高编程效率
在调用函数是当指针指向变量的值改变时,这些值能够为主调函数使用,即可以从函数调用得到更多个可改变的值