在介绍字符型数组与指针的关系前,先回忆一下字符型数组:
字符数组是C语言中存储字符串的基本方式,它的特点如下:
-
在内存中连续存储;
-
以'\0'作为字符串结束标志;
-
数组名代表数组首地址。
字符指针
字符指针可以指向字符串常量
cs
char *p = "Hello";
字符串常量存放在字符串常量区,当指针指向字符串常量时,其内容不可以被更改。
这是因为指针变量本身存储在栈区或者静态区,其指向的的字符串存储在只读数据段,也就是字符串常量区。
关键字:const
const用于定义常量,表示被修饰的内容不能被修改。
其作用:保护数据不被意外修改,提高代码可读性。
const与指针结合时较为复杂,比如:
指向常量的指针(指针可变,指向的内容不可变)
cs
const int *p ;
int a = 10;
p = &a;
//*prt = 20; //错误:不能通过p修改a的值
a = 20; //直接修改a是可以的
常量指针(指针不可变,指向的内容可变)
cs
int b = 20;
int *const p = &b;
*p = 40;
//p = &a; // 不能改变p的指向
const与数组
cs
const int a = {1,5,6,2,8,9};
a[0] = 2; //不能修改const的数组元素
(注:const变量必须初始化)
void *
其表示万能指针,但不能进行指针运算。
将一个字符型数组中的值复制给另一个字符型数组时,了解到字符型数组的复制需要调用strcpy函数,要是复制整形数组,我们只需要调用memcpy函数,其内核与strlen大相径庭,如下
cs
#include <stdio.h>
void Memcpy(void *dest,void *src,int n)
{
char *p = (char *)dest;
char *q = (char *)src;
while(n--)
{
*p++ = *q++;
}
}
int main(void)
{
int a[10] = {1,2,3,4,5,6,7,8,9,0};
int b[10];
Memcpy(b,a,sizeof(a));
for(int i = 0,i < 10;++i)
{
printf("%d\n",b[i]); //运行后,就能清楚的看到将数组a复制到了数组b
}
return 0;
}
(memcpy函数时一个字节一个字节的复制,所以传的参数就是数组的字节长度)
万能指针的基类型时 void *,它降低了程序额耦合性。
数组指针
数组指针 int (*p)[10]:指向数组的指针,基类型为int [10](即长度为10的一维整形数组)
sizeof(p)= 40
(注:其中的括号不能省略,就变成了指针数组)
*(*(a + i) + j) * 等价于 a[ i ][ j ]
*a 表示第一行元素的地址,所以*(a+i)表示第 i 行元素的首元素地址;
*(a + i) + j :表示第 i 行第 j 列元素的地址;
*(*(a + i ) + j):表示第 i 行 第 j 列的值。
水平逆序二维数组
cs
void swap(int *a,int *b)
{
int t = *a,
*a = *b;
*b = t;
}
void reverse(int *begin,int *end)
{
while(begin < end)
{
swap(begin++ , end--);
}
}
void reverse2D(int (*a)[4],int rows)
{
int i,j;
for(i = 0;i < rows; ++i)
{
reverse(*(a + i),*(a + i) + 3);
}
}
二维数组作为函数传参,传递形参指向一维数组的指针。
指针函数
指针函数指的是返回值为指针的函数,它不能返回局部变量地址,但能返回静态变量,或者称其为全局变量。(static 关键字能修改变量的生存期)。
例子:标准函数库中的strcpy和strcat
cs
char *Strcpy(char *dest,const char *src)
{
char *ret = dest;
while(*dest)
{
++dest;
}
while(*src)
{
*dest++ = *src++;
}
*dest = 0;
return ret;
}
char *Strcat(char *dest,const char *src)
{
char *ret = *dest;
while(*dest)
{
++dest;
}
while(*src)
{
*dest++ = *src++;
}
*dest = 0;
return ret;
}
字符数组复制、连接、比较
(1)复制strcpy 与 strncpy
cs
void Strcpy(char *dest,char *src)
{
while(*src)
{
*dest++ = *src++;
}
*dest = '\0';
}
void Strncpy(char *dest,const char *src,int n)
{
while(*src && n--)
{
*dest++ = *src++;
}
*dest = 0;
}
strcpy是复制全部元素
strncpy是复制前 n 个元素
(2)strcat 与 strncat
cs
void Strcat(char *dest,const char *src)
{
while(*dest)
{
++dest;
}
while(*src)
{
*dest++ = *src++;
}
*dest = 0;
}
void Strncat(char *dest,const char *src,int n)
{
while(*dest)
{
dest++;
}
while(*src && n--)
{
*dest++ = *src++;
}
*dest = 0;
}
stccat是将数组src全部元素除了 '\0' 全部拷贝到数组dest
strncat是将数组src 前 n 个字符拷贝到数组dest
(3)strcmp 与 strncmp
cs
int Strcmp(const char *s1,const char *s2)
{
while(*s1 == *s2 && *s1 && *s2)
{
++s1;
++s2;
}
return *s1 - *s2;
}
int Strncmp(const char *s1,const char *s2,int n)
{
while(--n && *s1 == *s2 && *s1 && *s2)
{
++s1;
++s2;
}
return *s1 - *s2;
}
同理,两者的区别也是后者比较 s1 和 s2 前n个元素的大小