lesson 7 指针和数组
补充之前ifndef部分
它是if not define 的简写,是宏定义的一种,实际上确切的说,这应该是预处理功能三种(宏定义、文件包含、条件编译)中的一种----条件编译。
在c语言中,对同一个变量或者函数进行多次声明是不会报错的。所以如果h文件里只是进行了声明工作,即使不使用# ifndef宏定义,多个c文件包含同一个h文件也不会报错。
但是在c++语言中,#ifdef的作用域只是在单个文件中。所以如果h文件里定义了全局变量,即使采用#ifdef宏定义,多个c文件包含同一个h文件还是会出现全局变量重定义的错误。
使用#ifndef可以避免下面这种错误:如果在h文件中定义了全局变量,一个c文件包含同一个h文件多次,如果不加#ifndef宏定义,会出现变量重复定义的错误;如果加了#ifndef,则不会出现这种错误。
#ifndef x //先测试x是否被宏定义过 #define x 程序段1blabla~ //如果x没有被宏定义过,定义x,并编译程序段 1 #endif 程序段2blabla~ //如果x已经定义过了则编译程序段2的语句,“忽视”程序段 1
条件指示符#ifndef 的最主要目的是防止头文件的重复包含和编译。了解:条件编译当然也可以用条件语句来实现。 但是用条件语句将会对整个源程序进行编译,生成的目标程序程序很长,而采用条件编译,则根据条件只编译其中的程序段1或程序段2,生成的目标程序较短。如果条件选择的程序段很长,采用条件编译的方法是十分必要的。
#ifndef 和 #endif 要一起使用,如果丢失#endif,可能会报错。总结一下:在c语言中,对同一个变量或者函数进行多次声明是不会报错的。所以如果h文件里只是进行了声明工作,即使不使用# ifndef宏定义,一个c文件多次包含同一个h文件也不会报错。 使用#ifndef可以避免下面这种错误:如果在h文件中定义了全局变量,一个c文件包含同一个h文件多次,如果不加#ifndef宏定义,会出现变量重复定义的错误;如果加了#ifndef,则不会出现这种错.
#ifdef
与ifndef类似,ifdef顾名思义,就是if define,看例子
#ifdef x 程序1blabla~ #endif
翻译:如果宏定义了x,则执行程序1.
此外,还有其他形式,还是看例子好些:
#ifndef x #define x 程序段 1 #else 程序段 2 #endif
当x没有由#define定义过,则编译“程序段1”,否则编译“程序段2”。
#if 表达式 程序段 1 #else 程序段 2 #endif
它的作用是 当“表达式”值为真时。编译程序段1。否则则编译程序段2。当没有程序段2时,直接是#if---#endif
#define
在C或C++语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。“define”为宏定义命令。
被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。
优点:
(1) 方便程序的修改。这个就不多说了。
(2) 提高程序的运行效率。使用带参数的宏定义可完成函数调用的功能,又能减少系统开销,提高运行效率。正如C语言中所讲,函数的使用可以使程序更加模块化,便于组织,而且可重复利用,但在发生函数调用时,需要保留调用函数的现场,以便子函数执行结束后能返回继续执行,同样在子函数执行完后要恢复调用函数的现场,这都需要一定的时间,如果子函数执行的操作比较多,这种转换时间开销可以忽略,但如果子函数完成的功能比较少,甚至于只完成一点操作,如一个乘法语句的操作,则这部分转换开销就相对较大了,但使用带参数的宏定义就不会出现这个问 题,因为它是在预处理阶段即进行了宏展开,在执行时不需要转换,即在当地执行。宏定义可完成简单的操作,但复杂的操作还是要由函数调用来完成,而且宏定义所占用的目标代码空间相对较大。所以在使用时要依据具体情况来决定是否使用宏定义。
在C或C++语言中,“宏”分为有参数和无参数两种。
一、无参宏定义
1. 无参宏定义的一般形式为:#define 标识符 字符串
2. 其中的“#”表示这是一条[预处理命令](http://baike.baidu.com/view/1334643.htm)。凡是以“#”开头的均为[预处理命令](http://baike.baidu.com/view/1334643.htm)。“define”为[宏定义](http://baike.baidu.com/view/2076445.htm)命令。“[标识符](http://baike.baidu.com/view/390932.htm)”为所定义的宏名。“字符串”可以是常数、[表达式](http://baike.baidu.com/view/420676.htm)、格式串等。
[](javascript:void(0)??
1 #include
2 #define M ( a+b ) 3 int main( int argc, char * argv[] ) 4 { 5 int s, a, b; 6 printf( "input number a& b: " ); 7 scanf( "%d%d", &a, &b ); 8 s = M*M; 9 printf( "s=%d\n" ,s ); 10 } [](javascript:void(0)??
上例程序中首先进行宏定义,定义M来替代表达式(a+b),在 s= M * M 中作了宏调用。在预处理时经宏展开后该语句变为: S=(a+b)(a+b) 但要注意的是,在宏定义中表达式(a+b)两边的括号不能少。否则会发生错误。 如当作以下定义后:#define M (a)+(b) 在宏展开时将得到下述语句:S= (a)+(b)(a)+(b)
还要说明的是:
1.宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。
2.宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。
3..宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令
二、带参宏定义
c语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。
带参宏定义的一般形式为: #define 宏名(形参表) 字符串
例:
#define M(y) ((y)*(y)+3*(y)) /*宏定义*/ k = M(5); /*宏调用*/
[](javascript:void(0)??
#include
#define MAX( a, b ) ((a>b)?(a):(b)) int main( int argc, char * argv[] ) { int x, y, max; printf( "input two numbers: " ); scanf( "%d%d", &x, &y ); max = MAX( x, y ); printf( "max=%d\n", max ); return 0; } [](javascript:void(0)??
上例程序的第一行进行带参宏定义,用宏名MAX表示条件表达式 (a>b)?a:b ,形参a,b均出现在条件表达式中。程序中 max=MAX(x,y) 为宏调用,实参x,y,将代换形参a,b。宏展开后该语句为: max=(x>y)?x:y; 用于计算x,y中的大数。
7.指针
7.1 概述
查看内存地址的方法:
int是4字节的,一个字节八位,可以存储两个16进制数,所以aa在一个地址里,bb在一个地址里.......
7.2 指针基础知识
#include
int main()
{
int a = 0xaabbccdd;
//a =100;
printf("%p\n", &a);
getchar();
return 0;
}
输出:0073F748
在基本数据类型后加上*,表示指针数据类型,如int* p
*为取值运算符,使用方法:*加上指针变量
int main()
{
//定义指针变量存储地址
int a = 10;
int* p;
p = &a;
*p = 100;
printf("%p\n", &a);
printf("%p\n", p);
printf("%d\n", a);
printf("%d\n", *p);
return 0;
}
输出:
009CFB5C
009CFB5C
100
100
测试指针地址占用数据内存大小:
int main()
{
int a = 10;
int* p = &a;
printf("%d\n", sizeof(int*));
}
64位输出是8, ×86输出是4.
所有的指针存储的都是内存地址,内存地址都是一个无符号十六进制整型数,具体占得字节大小是由操作系统决定的。
&是取地址符号,是升维度的;*是取值符号,是降维度的
int main()
{
char ch = 'a';
int* p = &ch;
printf("%p\n", p);
printf("%p\n", &ch);
printf("%d\n", ch);
printf("%d\n", *p);
return 0;
}
输出:
006FF92B
006FF92B
97
-858993567
在指针赋值时,一定要注意指针类型要和被赋值的类型一样,不然会出错
int* p 会找寻四个char* p的地址,输出就是一堆乱码了
#include
int main()
{
int* p;
printf("%d\n", &p);
printf("%p\n", &p);
return 0;
}
输出:
17823808
010FF840
野指针:
#include
int main()
{
//野指针——指针变量指向一个未知的空间,程序中允许存在野指针
int* p=100;//直接把内存地址为100的内存分配给了指针p,这个内存是否有值,是否能访问都是未知的
//操作系统将0-255作为系统占用,不允许访问操作。
//操作野指针对应的内存空间可能会报错
printf("%d\n", *p);
return 0;
}
没有任何输出,调试会报错的
空指针:
int main()
{
//空指针是内存地址编号为0的空间
int* p = NULL;
//操作空指针对应的空间一定会报错
*p = 100;//写入会报错
printf("%d\n", *p);//读取会报错
//空指针可以用作条件判断,if(p==NULL){}
return 0;
}
万能指针void:
void *指针可以指向任意变量的内存空间:
#include
int main()
{
int a = 10;
//int* p = &a;
//万能指针可以接收任意变量类型的内存地址
void* p = &a;
//在通过万能指针修改变量的值时,需要找到变量对应的指针类型
//*p = 100;
*(int*)p = 100;
printf("%d\n", a);
printf("%d\n", *(int*)p);
printf("万能指针在内存中占得字节大小:%d\n", sizeof(void*));
return 0;
}
输出:
100
100
万能指针在内存中占得字节大小:4
const修饰的指针变量
#include
int main()
{
const int a = 10;
int* p = &a;
*p = 100;//指针间接修改常量的值
printf("%d\n", a);//这里可以把a的值修改成100.
return 0;
}
输出:100
int main()
{
int a = 10;
int b = 20;
const int* p = &a;
//*p = 100;//err
p = &b;//ok
printf("%d\n", *p);
return 0;
}
输出:20
int main()
{
int a = 10;
int b = 20;
int* const p = &a;
//p = &b;//err
*p = 200;
printf("%d\n", a);
return 0;
}
输出:200
- const修饰指针类型:可以修改指针变量的值,不可以修改指针指向的内存空间
- const修饰指针变量:可以修改指针指向内存空间的值,不可以修改指针变量的值
int main()
{
int a = 10;
int b = 20;
const int* const p = &a;
printf("%d\n", *p);
int** pp = &p;//二级指针,可以用于修改一级指针的值
*pp = &b;
printf("%d\n", *p);
**pp = 100;
printf("%d\n", *p);//通过二级指针也可以直接修改*p的值
return 0;
}
输出:
10
20
100
7.3 指针和数组
数组可以理解为首地址+[]个下标地址偏移值
指针类型变量 +1 等同于内存地址+sizeof(int等指针数据类型)
#include
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,'a','b' };
//数组名是数组首元素的地址
int* p = arr;
printf("p=%p\n", p);
printf("arr=%p\n", arr);
*p = 123;
for (int i = 0; i < 11; i++)
{
//printf("%d\n", arr[i]);
printf("%d\t", p[i]);
}
printf("\n");
for (int i = 0; i < 11; i++)
{
//printf("%d\n", arr[i]);
printf("%d\t", *(arr+i));//通过地址+偏移量的方式输出数组
}
printf("\n");
for (int i = 0; i < 11; i++)
{
//printf("%d\n", arr[i]);
printf("%d\t", *(p+i));//通过移动指针来输出数组
}
putchar(10);
printf("%d\n", *p);
putchar(10);
//移动指针,用赋值语法
for (int i = 0; i < 11; i++)
{
//printf("%d\n", arr[i]);
printf("%d\t", *p++);//*取值优先于自加
}
putchar(10);
int step = p - arr;//两指针相减,得到的是两个指针的偏移量(步长)
//所有的指针相减,结果都是int类型的
printf("%d\n", step);
return 0;
}
输出:
p=001AFB10
arr=001AFB10
123 2 3 4 5 6 7 8 9 97 98
123 2 3 4 5 6 7 8 9 97 98
123 2 3 4 5 6 7 8 9 97 98
123
123 2 3 4 5 6 7 8 9 97 98
11
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//指向数组的指针
int* p = arr;
//区别:p是变量 arr是常量
printf("指针类型大小:%d\n", sizeof(p));
printf("数组大小:%d\n", sizeof(arr));
//p是一个指针,4字节大小。arr是一个数组,40字节大小
//方法一:p[i];
//方法二:*(p+i);
return 0;
}
输出:
指针类型大小:4
数组大小:40
不能在bubblesort里面写len=sizeof(arr)/sizeof(arr[0]),因为传参的时候会把数组传成一个一个的值,所以无论数组多大,len都等于1
void BubbleSort(int arr[],int len)//数组作为参数会退化为指针 丢失了数组的精度(元素个数),所以必须要通过传参传过来
{
for (int i = 0; i < len-1; i++)
{
for (int j = 0; j < len-1-i; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
int main()
{
int arr[] = { 9,1,2,6,5,7,4,3,10,8 };
BubbleSort(arr, 10);
for (int i = 0; i < 10; i++)
{
printf("%d\t", arr[i]);
}
return 0;
}
输出:1 2 3 4 5 6 7 8 9 10
指针拷贝数组字符串的方法:
#include
void my_strcpy(char* dest, char* ch)
{
int i = 0;
while (ch[i] != '\0')//记住是反斜杠,第一次写成/0报错了,会是无限循环,导致越界
//可以写成while(ch[i]!=0)--->等同于while(ch[i])
{
dest[i] = ch[i];
i++;
}
dest[i] = 0;
}
void my_strcpy2(char* dest, char* ch)
{
int i = 0;
while (*(ch + i))
{
*(dest + i) = *(ch + i);
i++;
}
*(dest + i) = 0;
}
void my_strcpy3(char* dest, char* ch)
{
while (*ch)
{
*dest = *ch;
dest++;
ch++;
}
dest = 0;
}
void my_strcpy4(char* dest, char* ch)
{
while (*dest++ = *ch++);
}
int main()
{
//字符串拷贝
char ch[] = "hello world";
char dest[100];
my_strcpy(dest, ch);
printf("%s\t", dest);
return 0;
}
输出:hello world
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
int* p = arr;
//arr[-1] 数组下标越界
p = &arr[3];
//指针操作数组时,下标允许是负数
p--;//指针的加减运算与指针类型有关,如果是char就是-1了
printf("%p\n", p);
printf("%p\n", arr);
printf("%d\n", p[-2]);
}
输出:006FFC84
006FFC7C
1
指针运算
int main()
{
//指针和运算符的操作
int arr[] = { 1,2,3,4,5,6,7,8,9 };
int* p = arr;
p = &arr[3];
//p = p + arr;//报错,+不能添加两个指针,两个指针相加一定是野指针,加减乘除取余都不能对两个指针运算
if (p > arr)//可以比大小
{
printf("真\n");
}
return 0;
}
输出:真
指针数组
数组中的每一个元素都是指针类型
#include
int main()
{
int a = 10;
int b = 20;
int c = 30;
int* arr[3] = { &a,&b,&c };//定义指针数组
printf("%d\n", *arr[0]);
printf("指针数组大小为:%d\n", sizeof(arr));
printf("指针元素大小为:%d\n", sizeof(arr[0]));
return 0;
}
输出:
10
指针数组大小为:12
指针元素大小为:4
int main()
{
//指针数组里面的的元素都是指针
int a[] = { 1,2,3 };
int b[] = { 4,5,6 };
int c[] = { 7,8,9 };
int* arr[] = { a,b,c };//指针数组相当于二级指针,因为存放的是数组的地址
//在定义的时候可以写成int** p = arr;
printf("%p\n", arr[0]);
printf("%p\n",a );
printf("%p\n", arr);//arr是指针数组的首地址
printf("%p\n",&a[0] );
for (int i = 0; i < 3 ; i++)
{
for (int j = 0; j < 3; j++)
{
//用二维数组方式打印出值
printf("%d\t", arr[i][j]);//a[i]就是数组的首地址,在后面加上[j],就是数组寻址,所以不需要加指针符号来取值
}
putchar(10);
}
//方法二:
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
printf("%d\t", *(arr[i]+j));//地址加偏移量,然后*取地址的值
}
putchar(10);
}
//方法三:
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
printf("%d\t", *(*(arr+i) + j));//地址加偏移量,然后*取地址的值
}
putchar(10);
}
return 0;
}
输出:
0053FDE8
0053FDE8
0053FDAC
0053FDE8
1 2 3
4 5 6
7 8 9
1 2 3
4 5 6
7 8 9
1 2 3
4 5 6
7 8 9
多级指针:**ppp*ppp==&a
7.5 指针和函数
值传递和地址传递
值传递:形参不影响实参的值
地址传递,形参可以改变实参的值,前提是形参比实参底层一级
#include
void swap(int* a, int* b)//指针作为函数参数
{
int temp = *a;//这里主要要改变的都是值,而不是地址
*a = *b;
*b = temp;
}
int main()
{
int a = 10;
int b = 20;
//指针作为函数参数时,传递的是地址
swap(&a, &b);//地址传递,形参可以改变实参的值
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
输出:
20
10
数组名作为函数参数
#include
//数组写法
void my_strcat(char* ch1,char* ch2)//因为字符串数组是以\0结尾的,所以不需要传递数组精度
{
int i = 0;
while (ch1[i]!='\0')
{
i++;
}
printf("%d\n", i);//5
printf("%d\n", strlen(ch1));//系统提供的函数,5
int j = 0;
while (ch2[j] != '\0')
{
ch1[i + j] = ch2[j];
j++;
}
}
//指针写法
void my_strcat2(char* ch1, char* ch2)
{
int i = 0;
while (*(ch1 + i) != '\0')
{
i++;
}
int j = 0;
while (*(ch2+j) != '\0')
{
*(ch1+i + j) = *(ch2+j);
j++;
}
}
void my_strcat3(char* ch1, char* ch2)
{
while (*ch1)ch1++;
while (*ch2)
{
*ch1 = *ch2;
ch1++;
ch2++;
}//因为ch1后面100之前都是0,所以这里不需要额外加0
}
void my_strcat4(char* ch1, char* ch2)
{
while (*ch1)ch1++;
while (*ch1++ = *ch2++);
}
int main()
{
char ch1[100] = "hello";
char ch2[] = "world";
my_strcat3(ch1,ch2);
printf("%s\n", ch1);
return 0;
}
输出:helloworld
字符串去空格:
void remove_space(char* ch)
{
char str[100] = { 0 };
int i = 0;
int j = 0;
char* temp = str;
while (ch[i] != '\0') {
if (ch[i] != ' ') {
str[j] = ch[i];
j++;
}
i++;
}
while (*ch++ = *temp++);
}
void remove_space2(char* ch)
{
char* ftemp = ch;//用来遍历字符串
char* rtemp = ch;//记录非空格字符串
while (*ftemp) {
if (*ftemp != ' ')
{
*rtemp = *ftemp;
rtemp++;
}
ftemp++;
}
*rtemp = 0;
}
int main()
{
char ch[] = " h ello , worl d ";
remove_space2(ch);
printf("%s\n", ch);
return 0;
}
输出:hello,world
指针作为函数返回值
#include
char* my_strchr1(char* ch, char l)
{
int i = 0;
while (ch[i])
{
if (ch[i] == l)
{
return &ch[i];
}
i++;
}
return NULL;
}
char* my_strchr2(char* ch, char l)
{
while (*ch)
{
if (*ch == l)
{
return ch;
ch++;
}
return NULL;
}
}
int main()
{
char ch[] = "helloworld";
char* p = my_strchr2(ch, 'm');
if (p == NULL)
{
printf("未找到");
}
else
{
printf("%s\n", p);
}
return 0;
}
输出:未找到
查找字符串
#include
char* my_strstr(char* src,char* dest )
{
char* fsrc = src;//定义遍历原字符串的指针
char* rsrc = src;//记录查找到的字符串的首地址
char* tdest = dest;
while (*fsrc)
{
rsrc = fsrc;
while (*fsrc == *tdest&&*fsrc!='\0')//如果是最后几个字符相同,则需要后面的条件判断,否则判断\0会导致数组下标越界
{
fsrc++;
tdest++;
}
if (*tdest=='\0')
{
return rsrc;
}
//如果不一样,则需要目标指针回指第一个字符
tdest = dest;
fsrc = rsrc;
fsrc++;
}
return NULL;
}
int main()
{
char src[] = "hello world";
char dest[] = "llo";
char* p = my_strstr(src, dest);
printf("%s\n", p);
return 0;
}
输出:llo world
7.6 指针和字符串
7.6.1 字符指针
#include
int main()
{
char ch[] = "hello world";//栈区字符串,可以被用下标和指针方式修改
char* p = "hello world";//数据区常量区字符串,不可以被修改
char* p1 = "hello world";
//ch[2]='m'; 是可以通过的,修改了ch[]中的值
//p[2]或者是*(p+2)='m',是会报错的。无法写入
printf("%p\n", p);
printf("%p\n", p1);//因为是只读的,所以一样的内容只需要保存一次,多个指针可以指向同一个地址
return 0;
}
输出:
00897B30
00897B30
int main()
{
//字符串数组,指针数组
char ch1[] = "hello";
char ch2[] = "world";
char ch3[] = "dabaobei";
char* arr[] = { ch1,ch2,ch3 };//可以被修改
//字符串数组
char* arr[] = { "hello","world","dabaobei" };//这是存储在常量池里的,不能被修改
return 0;
}
7.6.2字符指针作函数参数
#include
int my_strlen(ch)
{
char* temp = ch;
while (*temp != '\0')temp++;
return temp - ch;
}
int main()
{
char ch[] = "hello world";
int len = my_strlen(ch);
printf("%d\n", len);
return 0;
}
输出:11
7.6.3 const修饰的指针变量
#include
int main()
{
char ch1[] = "hello";
char ch2[] = "world";
const char* p = ch1;
//指向常量的指针
//可以修改指针变量的值,不可以修改指针变量指向内存空间的值
p = ch2;
for (int i = 0; i < 5; i++)
{
printf("%c", *(p+i));
}
return 0;
}
输出:world
int main()
{
char ch1[] = "hello";
char ch2[] = "world";
char* const p = ch1;
//可以修改指针变量指向空间的值,不可以修改指针变量的值
p[2] = 'm';
*(p + 1) = 'a';
printf("%s\n", p);
printf("%s\n", ch1);
return 0;
}
输出:
hamlo
hamlo
7.6.4 主函数参数
#include
int main(int argc,char* argv[])//argc表示传递参数的个数,argv用来保存传递的字符串
{
for (int i = 0; i < argc; i++)
{
printf("%s\n", argv[i]);
}
return 0;
}
gcc编译不通过先检查下语法,然后看下是不是写完然后保存了。
7.6.5 常用字符串应用模型
#include
int strlen(ch)
{
char* temp = ch;
while (*temp != '\0')temp++;
return temp - ch;
}
int main()
{
char ch[] = "dasjfdsfn dsancixjzicnmcnekwlj kladsdkfksfnkdasnfkljdsalkfndsa";
int arr[26] = { 0 };//存储字符串出现的个数
for (int i = 0; i < strlen(ch); i++)
{
arr[ch[i] - 'a']++;//0-26每一个字母遇到,在arr数组里就给相对应的数字+1
}
for (int i = 0; i < 26; i++)
{
if (arr[i])
{
printf("字母%c出现的次数为:%d\n", 'a' + i, arr[i]);
}
}
return 0;
}
输出:字母a出现的次数为:6
字母c出现的次数为:3
字母d出现的次数为:8
字母e出现的次数为:1
字母f出现的次数为:6
字母i出现的次数为:2
字母j出现的次数为:4
字母k出现的次数为:7
字母l出现的次数为:4
字母m出现的次数为:1
字母n出现的次数为:7
字母s出现的次数为:8
字母w出现的次数为:1
字母x出现的次数为:1
字母z出现的次数为:1
字符串逆置:
#include
void inverse(char* ch)
{
int i = 0;
int j = strlen(ch) - 1;
while (i < j)
{
char temp = ch[j];
ch[j] = ch[i];
ch[i] = temp;
i++;
j--;
}
return;
}
void inverse2(char* ch)
{
char* ftemp = ch;
char* btemp = ch + strlen(ch) - 1;
while (ftemp
输出:dlrow,olleh
回文字符串:
//回文字符串(对称的字符串),如abccba
int symm(char* ch)
{
char* ftemp = ch;
char* btemp = ch + strlen(ch) - 1;
while (ftemp
输出:是回文字符串
7.6.6 字符串处理函数
需要导入string.h头文件
-
strcpy():char* strcpy(char* dest, const char *src)
把src所指向的字符串复制到dest所指向的空间中,\0也会被烤进去。如果参数dest所指向的内存空间不够大,可能会造成缓冲溢出的错误情况,是一个不安全的行为,需要在头文件#define一下
int main() { char ch[] = "helloworld"; char str[100]; strcpy(str, ch); printf("%s\n", str); return 0; }
输出:helloworld
-
strncpy(): char* strncpy(char* dest , const char *src,size_t n);
把src指向的字符串前n个字符复制到dest所指向的空间,是否拷贝结束看的是指定长度是否包含'\0';
#include
int main() { char ch[] = "helloworld"; char str[100] = { 0 };//这里如果不初始化,拷贝的字符串不到含有\0,会有乱码 //strcpy(str, ch);//字符串拷贝 strncpy(str, ch, 5); printf("%s\n", str); return 0; } 输出:hello
-
strcat() : char* strcat(char* dest,const char* src);功能是将src字符串连接到dest的尾部。
#include
void my_strcat(char* dest, char* src) { while (*dest)dest++; while (*dest++ = *src++); } int main() { char dest[100] = "hello"; char src[] = "world"; my_strcat(dest, src); printf("%s\n", dest); return 0; } 输出:helloworld
-
strncat() : char* strncat(char* dest, const char* src, size_t n);
功能:将src字符串前n个字符连接到dest 的尾部,‘\0’也会被追加过去。
实现方法:
void my_strncat(char* dest, char* src, int n) { while (*dest)dest++; while ((*dest++ = *src++)&&--n); }
-
strcmp() : int strcmp(const char* s1,const char* s2)
功能:比较s1,s2的大小,比较的是ASCII码的大小。相等:0,大于:>0,小于:<0.返回的是ASCII码的差值,或者-1,1
-
strncmp() : int strncmp(const char* s1,const char* s2,size_t n) : 比较前n个字符的大小
#include
int main() { char ch1[] = "hello world"; char ch2[] = "hello world"; int value = strcmp(ch1, ch2); printf("%d\n", value); return 0; } 输出:0
-
sprintf() : 导入stdio库,Int sprintf(char *str, const char *format,...) : 功能 :根据参数format字符串来转换并格式化数据,然后将结果输出到str指定的空间中,直到出现字符串结束符'\0'为止。
format是字符串格式,跟printf一样。
#define _CRT_SECURE_NO_WARNINGS #include
int main() { char ch[100]; sprintf(ch, "hello world"); sprintf(ch, "%02d+%02d=%02d", 1, 2, 3); sprintf(ch, "%x+%o=%d", 1234, 2312, 3); printf("%s\n", ch); return 0; } 输出:4d2+4410=3
-
sscanf : int sccanf(const char * str,const char* format,...);
功能:从str指定的字符串读取数据,并根据参数format字符串来转换并格式化数据。sscanf(src,"a=%d,b=%d,&a,&b);
-
strchr() : string.h库,在字符串s中查找字母c出现的位置
char* strchr(const char* s,int c);
#define _CRT_SECURE_NO_WARNINGS #include
int main() { char ch[] = "helloworld"; char c = 'l'; char* p = strchr(ch, c); printf("%s\n", p); return 0; } 输出:lloworld
-
strstr():省略
-
strtok : 功能是将字符串分割成一个个片段。当strtok()在参数s的字符串中发现参数delim中包含的分割字符时,则会将该字符改为0字符,当连续出现多个时只替换第一个为\0。
char* strtok(char str,const char delim)
#define _CRT_SECURE_NO_WARNINGS #include
int main() { char ch[] = "www.baidu.com";//strtok字符串截取会破坏原字符串,会用\0替换分隔的标志位 //www\0baidu.com char* p = strtok(ch, "."); printf("%s\n", p); printf("%s\n", ch); printf("%p\n", p); printf("%p\n", ch); p = strtok(NULL, ".");//www\0baidu\0com printf("%s\n", p); p = strtok(NULL, "."); printf("%s\n", p); return 0; } 输出:
www
www
007BF7B0
007BF7B0
baidu
com -
atoi() : stdlib.h库,
int atoi(const char* nptr);
功能:atoi()会扫描nptr字符串,跳过前面的空格字符,直到遇到数字或正负号才开始做转换,而遇到非数字或者字符串结束符(‘\0’)才会结束转换,并将结果返回返回值。
atof()转化成浮点型,atol()转换成long类型
#define _CRT_SECURE_NO_WARNINGS #include
#include int main() { char ch[] = " -123456abc123"; int i = atoi(ch); printf("%d\n", i); return 0; } 输出:-123456