《C和指针》-课后习题

一、指针

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];

}

猜你喜欢

转载自blog.csdn.net/Forever_change/article/details/133941218