一、指针
1.请编写一个函数,它在一个字符串中进行搜索,查找第一个在给定字符集合中出现的字符。这个函数的原型如下:
char *find_char(char const *source,char const *chars)
#include<stdio.h>
/*功能与c函数库中名叫strpbrk函数类型*/
char *find_char(char const *source,char const *chars)
{
char const *pc = chars;
char const *ps = source;
/*如果传入的是空指针*/
if(ps == NULL || pc == NULL)
{
return NULL;
}
/*如果指针移动到字符串的最后*/
if(*ps == '\0' || *pc=='\0')
{
return NULL;
}
while (*ps !='\0')
{
while (*pc != '\0')
{
if(*ps == *(pc++))
return (char *)ps;
}
pc = chars;
ps++;
}
return NULL;
}
int main(void)
{
const char * source = "ABCDEF";
const char * chars = "XYZ";
char * res = find_char(source, chars);
if (res == NULL)
{
printf("res = NULL\n");
}
else
{
printf("res = %c\n", *res);
}
return 0;
}
2. 编写一个函数,删除一个字符串的一部分。函数的原型如下:
int del_substr(char *str,char const *substr)
#include <stdio.h>
int StringLen(char const *str)
{
int i,sum=0;
for(i=0;str[i]!='\0';i++){
sum++;
}
return sum;
}
int del_substr(char *str,char const *substr)
{
/*声明一个指针ps指向str*/
char *ps = str;
char const *psu = substr;
int start=0,end = 0;
int len = StringLen(substr);
int flag = 0;
while (*ps != '\0')
{
end++;
if(*ps == *psu)
psu++;
else
psu = substr;
ps++;
if(*psu == '\0')
{
flag = 1;
break;
}
}
start = end-len;
while ((start--)>0)
{
str++;
}
while (*ps != '\0')
{
*(str++) = *(ps++);
}
*str = '\0';
printf("%s\n",str);
return flag;
}
int main(void)
{
char str[] = "ABCDEFG";
char const *substr = "CDE";
int p ;
p = del_substr(str,substr);
printf("%d\n",p);
printf("%s\n",str);
}
在写上述代码的时候出现了两个问题:
程序报错:Program received signal SIGSEGV,Segmentation fault。执行到(*str++) = (*ps++)会报错。
原因:最开始的变量初始化 char *str = "ABCDEFG"; str指向的是只读常量区,所以执行到(*str++) = (*next++)会报错,该语句试图改变只读常量区里的值时,操作系统向程序发送了一个信号,告诉程序操作系统检测到了非法的内存访问,为了防止内存空间被破坏,操作系统提前终止了该程序的运行; 用数组声明即可 char str[] = "ABCDEFG";
"ABCDEFG"属于常量,在内存中存储在静态存储区域,常量是不允许修改的。
数组声明
程序结果不对:当str[]="ABCDEFG" substr="F" 的时候显示的是空。
原因:在代码调试的时候发现,不管substr="F"还是substr="CDF"的时候sizeof(substr)的值都是8,因为sizeof是一个判断数据类型或者表达式长度的运算符。所以输出的实际是一个指针为8个字节。因此在上述代码中加入自定义的函数StringLen()。
3. 编写函数reverse_string,它的原型如下:
void reverse_string(char *string)
函数把参数字符串中的字符反向排列。
#include <stdio.h>
/**
* 字符反向排列
*/
void reverse_string(char *str)
{
char *p = str;
char temp;
/*获取数组的长度*/
int len = sizeof(str) / sizeof(char);
int i = 0;
/*借助一个p指针指向数组,并将该指针移动到数组的末尾*/
while (*(p++) != '\0')
;
p--;
p--;
/*首和末进行调换*/
while((i++) <= (len/2)-1)
{
/**/
temp = *p;
/*将*/
*p = *str;
/**/
*str = temp;
p--;
str++;
}
printf("%s\n",str);
}
int main(void)
{
char str[] = "abcdefg";
printf("%s\n",str);
reverse_string(str);
printf("%s\n",str);
return 0;
}
思想:
1. 定义一个指针p,并让它指向传输过来的字符串char *p=str。
2. 让这个指针指向字符串的末尾。
3. 对整个字符串进行对半划分,左半边和右半边进行对换。
二、结构和联合
1. 成员和数组元素有什么区别?
数组和结构相似的地方是都不再是单一的原子类型,而是一个集合。
区别在于数组是相同类型元素(元素可以是原子类型的整型、浮点型、字符型或者结构体、数组等)的集合,而结构是不同类型元素的集合。所以结构无所不包,当然结构中可以定义相同类型的元素,而数组则不然。
2. 结构名和数组名有什么不同?
结构名是一个标量。与其他任何变量一样,当结构名在表达式中作为右值使用的时候,表示存储在结构中的值;作为左值的时候使用时,表示结构存储的内存位置。但是,当数组名在表达式作为右值使用时,它的值是一个指向数组第1个元素的指针。
3. 在拨打长途电话时,电话公司所保存的信息会包括拨打电话的日期和时间。它还包括3个电话号码:使用的那个电话、呼叫的那个电话以及付账的那个电话。这些电话号码的每一个都由3个部分组成:区号、交换台和站号码。请为这些记账信息编写一个结构声明。
/*
表示长途电话付账记录的结构
*/
struct PHONE_NUMBER{
short area;
short exchange;
short station;
};
struct LONG_DISTANCE_BILL{
short month;
short day;
short year;
int time;
struct PHONE_NUMBER called;
struct PHONE_NUMBER calling;
struct PHONE_NUMBER billed;
}
另一个方法是使用一个长度为PHONE_NUMBERS的数组。如下所示:
/*
表示长途电话付账记录的结构
*/
enum PN_TYPE{CALLED,CALLING,BILLED};
struct LONG_DISTANCE_BILL{
short month;
short year;
short day;
int time;
struct PHONE_NUMBER numbers[3];
}