c和指针练习题

/*
1.请编写一个函数,它在一个字符串中进行搜索,查找所有在一个给定字符集合中出现的字符。这个函数的原型应该如下:
char *find_char( char const *source,  char const *chars );
它的基本想法是查找source字符串中匹配chars字符串中任何字符的第1个字符,函数然后返回一个指向source中第1个匹配所找到的位置的指针。如果source中的所有字符均不匹配chars中的任何字符,函数就返回一个NULL指针。如果任何一个参数为NULL,或任何一个参数所指向的字符串为空,函数也返回一个NULL指针。
举个例子,假定source指向ABCDEF。如果chars指向XYZ、JURY或QQQQ,函数就返回一个NULL指针。如果chars指向XRCQEF,函数就返回一个指向source中C字符的指针。参数所指向的字符串是绝不会被修改的。
碰巧,C函数库中存在一个名叫strpbrk的函数,它的功能几乎和这个你要编写的函数一模一样。但这个程序的目的是让你自己练习操纵指针,所以:
a.你不应该使用任何用于操纵字符串的库函数(如strcpy, strcmp, index等)。
b.函数中的任何地方都不应该使用下标引用。

*/
char * find_char(char const *source, char const *chars)
{
    printf("source:%s\n",source);
    printf("chars:%s\n",chars);
    char const *str;
    while(*source != '\0')
    {
        str = chars;				//===
        while(*str != '\0')
        {
            if(*source == *str )
            {
                return source;
            }
            str++;
        }
        source++;
    }
}

//6.19
/*
2.请编写一个函数,删除一个字符串的一部分。函数的原型如下:
 int del_substr( char *str, char const *substr )
函数首先应该判断substr是否出现在str中。如果它并未出现,函数就返回0;
如果出现,函数应该把str中位于该子串后面的所有字符复制到该子串的位置,
从而删除这个子串,然后函数返回1。如果substr多次出现在str中,函数只删除第1次出现的子串。
函数的第2个参数绝不会被修改。
举个例子,假定str指向ABCDEFG。如果substr指向FGH、CDF或XABC,
函数应该返回0,str未作任何修改。但如果substr指向CDE,函数就把str修改为指向ABFG,
方法是把F、G和结尾的NUL字节复制到C的位置,然后函数返回1。不论出现什么情况,
函数的第2个参数都不应该被修改。
和上题的程序一样:
a.你不应该使用任何用于操纵字符串的库函数(如strcpy, strcmp,等)。
b.函数中的任何地方都不应该使用下标引用。
一个值得注意的是,空字符串是每个字符串的一个子串,在字符串中删除一个空子串字符串不会产生变化。
*/


int del_substr( char *str, char const *substr )
{
	char const *substr_temp = substr;
    char *str_temp = str;
	int substr_len = 0;
	char *str_current;
	for(; *str_temp != '\0'; str_temp++)
	{
		if(*str_temp == *substr_temp)
		{
            str_current = str_temp;
			str_temp++;
			substr_temp++;
			for(;*substr_temp != '\0';substr_temp++)
			{
				if(*substr_temp == *str_temp)
				{
					str_temp++;
				}
				else
				{
					return 0;
				}
			}
            goto DEL;
		}
	}
	return 0;
DEL:
    /* get substr len */
    substr_temp = substr;
    while(*substr_temp != '\0')
    {
        substr_len++;
        substr_temp++;
    }
    /* str offset */
    while(*(str_current+substr_len) != '\0')
    {
        *str_current = *(str_current+substr_len);
        str_current++;
    }
    *str_current = '\0';

    return 1;
}

/*
3.编写函数reverse_string,它的原型如下:
 void reverse_string( char *string );
函数把参数字符串中的字符反向排列。请使用指针而不是数组下标,
不要使用任何C函数库中用于操纵字符串的函数。
提示:不需要声明一个局部数组来临时存储参数字符串。
*/

void reverse_string( char *string )
{
    char temp;
    char *str_temp = string;
    int str_len =  0;
    while(*str_temp != '\0')
    {
        str_len++;
        str_temp++;
    }

    for(int i = 0; i < (str_len/2); i++)
    {
        temp = *(string + i);
        *(string + i) = *(string +str_len-1 - i);
        *(string + str_len-1 - i) = temp;
    }
}

/*
4.质数就是只能被1和本身整除的整数。
Eratosthenes筛选法是一种计算质数的有效方法。
这个算法的第1步就是写下所有从2至某个上限之间的所有整数。
在算法的剩余部分,你遍历整个列表并剔除所有不是质数的整数。
后面的步骤是这样的。找到列表中的第1个不被剔除的数(也就是2),
然后将列表后面所有逢双的数都剔除,因为它们都可以被2整除,
因此不是质数。接着,再回到列表的头部重新开始,
此时列表中尚未被剔除的第1个数是3,所以在3之后把每逢第3个数(3的倍数)剔除。
完成这一步之后,再回到列表开头,3后面的下一个数是4,
但它是2的倍数,已经被剔除,所以将其跳过,轮到5,将所有5的倍数剔除。
这样依次类推、反复进行,最后列表中未被剔除的数均为质数。
编写一个程序,实现这个算法,使用数组表示你的列表。
每个数组元素的值用于标记对应的数是否已被剔除。
开始时数组所有元素的值都设置为TRUE,当算法要求“剔除”其对应的数时,
就把这个元素设置为FALSE。如果你的程序运行于16位的机器上,
小心考虑是不是需要把某个变量声明为long。一开始先使用包含1000个元素的数组。
如果你使用字符数组,使用相同的空间,你将会比使用整数数组找到更多的质数。
你可以使用下标来表示指向数组首元素和尾元素的指针,但你应该使用指针来访问数组元素。
注意除了2之外,所有的偶数都不是质数。稍微多想一下,
你可以使程序的空间效率大为提高,方法是数组中的元素只对应奇数。
这样,在相同的数组空间内,你可以寻找到的质数的个数大约是原先的两倍。
*/
void Eratosthenes(long n)
{
    int count = 0;
    bool array[n+1];
    array[0] = false;
    array[1] = false;
    for(long i = 2; i < n ; i++)
    {
        array[i] = true;
    }
    for(long i = 2; i < n ; i++)
    {
        if(array[i] == true)
        {
            for(long j = (i+i); j < n; j = j+i)
            {
                array[j] = false;
            }
        }
    }

    for(long i = 0; i < n ; i++)
    {
        if(array[i] == true)
        {
            count++;
            printf("%d\t",i);
            if(count >= 10 )
            {
                count = 0;
                printf("\n");
            }
        }
    }
}
/*
5.修改前一题的Eratosthenes程序,使用位的数组而不是字符数组,
这里要用到第5章编程练习中所开发的
位数组函数。这个修改使程序的空间效率进一步提高,
不过代价是时间效率降低。在你的系统中,使用这个方法,
你所能找到的最大质数是多少?
*/

/*
1.
Polynomials(厄密多项式)是这样定义的:

H(n)(x) = 1   								n <= 0
		= 2*x 								n = 1
		= 2xH(n-1)(x) - 2(n-1)H(n-2)(x)		n > 1
		
例如,H3(2)的值是40。请编写一个递归函数,计算Hn(x)的值。你的函数应该与下面的原型匹配:
 int hermite( int n, int x)
*/


int hermite(int n, int x )
{
    if(n <= 0 )
    {
        return 1;
    }
    else if(n == 1)
    {
        return 2*x;
    }
    else
    {
        return (2*x*hermite(n-1,x)) - (2*(n-1)*hermite(n-2,x));
    }
}


/*
2
两个整型值M和N(M、N均大于0)的最大公约数可以按照下面的方法计算:
gcd(M,N) = M%N = 0  		: N
		 = M%N = R,R>0  	: gcd(N,R)
请编写一个名叫gcd的函数,它接受两个整型参数,并返回这
两个数的最大公约数。如果这两个参数中的任何一个不大于零,函数应该返回零。

*/

int gcd( int m, int n)
{
	unsigned int r;
	if(m <= 0 || n <= 0)
	{
		return 0;
	}
	
	if(n > m)
	{
		r = m;
		m = n;
		n = r;
	}
	
	while(n > 0)
	{
		r = m % n;
		m = n;
		n = r;
	}
	return m;
}

/*
3
为下面这个函数原型编写函数定义:
  int ascii_to_integer( char *string );
这个字符串参数必须包含一个或多个数字,
函数应该把这些数字字符转换为整数并返回这个整数。
如果字符串参数包含了任何非数字字符,函数就返回零。
请不必担心算术溢出。提示:这个技巧很简单——你每发现一个数字,
把当前值乘以10,并把这个值和新数字所代表的值相加。


*/


int ascii_to_integer( char *string )
{
	int sum = 0;
	while(*string != '\0')
	{
		if(*string >= '0'  && *string <= '9')
		{
			sum *= 10;
			sum += *string - 0x30;
		}
		else
		{
			return 0;
		}
		string++;
	}
	return sum;
}

/*
4.编写一个名叫max_list的函数,
它用于检查任意数目的整型参数并返回它们中的最大值。
参数列表必须以一个负值结尾,提示列表的结束。

*/

int max_list(int n_values, ...)
{
    va_list v_list;
    int n = 0;
    int max = 0;

    /* 访问可变参数 */
    va_start(v_list,n_values);

    n = va_arg(v_list, int);
    while(n > 0)
    {
        if(n > max)
        {
            max = n;
        }
        n = va_arg(v_list, int);
    }
    va_end(v_list);
    return max;
}


/*
5.实现一个简化的printf函数,它能够处理%d、%f、%s和%c格式码。
根据ANSI标准的原则,其他格式码的行为是未定义的。
你可以假定已经存在函数print_integer和print_float,
用于打印这些类型的值。对于另外两种类型的值,使用putchar来打印。

*/

/*
6.编写函数
 void written_amount( unsigned int amount, char *buffer );
它把amount表示的值转换为单词形式,并存储于buffer中。
这个函数可以在一个打印支票的程序中使用。例如,如果amount的值是16 312,
那么buffer中存储的字符串应该是
 SIXTEEN THOUSAND THREE HUNDRED TWELVE
调用程序应该保证buffer缓冲区的空间足够大。
有些值可以用两种不同的方法进行打印。
例如,1 200可以是ONE THOUSAND TWO HUNDRED或TWELVE HUNDRED。
你可以选择一种你喜欢的形式。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值