这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 软件与操作系统 » 【学习会】一起学习C语言之重温C语言

共18条 2/2 1 2 跳转至
院士
2018-06-02 23:53:08     打赏
11楼
第六章、函数

函数,在我们的数学课程学习中已经学习与使用过无数次了。比如y = f(x)=kx+b 这样的一次函数,我们输入变量x,通过函数f(x)的计算能得出y的值。在C语言里,函数的作用与其是一样的,只是各个部分的名称略有不同:C语言里将y的值称为“返回值”;将f()称为函数名,并且要自己来定义,只要不重复即可。将变量x称为“形参”;当然,非常重要的 kx+b,函数体内的语句是需要我们自己编写。

当不需要返回值时,我们使用void来替代,称为无返回值函数(部分编程语言里称为过程)

当不需要传入参数时,我们也使用void来替代,称无参数函数,只是机械的执行内部语句。

对于形参,我们可以传入值,也可以传入地址。前者对于传入的变量不会改变其值,而后者,可以修改传入的变量,即实参的值。

本章还讲了变量的作用域,有函数内部的作用域,本文件的作用域,整个程序的作用域。这个道理很简单,在函数内部声明的变量,其作用域就在本函数内部,而声明在函数外的变量而使用了static关键字进行限定,则只限于本文件内部,否则,即为全局变量。

注意:我们在编写程序的时候,多少也要有些行规,像I,j,k这类的变量,只用于函数内部的局部变量,且仅用于计数使用;而全局变量在定义时,其要以gXX开头,这样不仅方便自己阅读代码,也方便别人阅读,万一人家看出程序的bug呢!

注意:文章内也提到,全局变量与函数内的局部变量可以一致,实参与形参也可以一致。但大家在编程的时候,千万不要这样做,时间一久,自己都忘了。属于自己给自己埋雷了。

函数的声明里,文章写了,要在函数定义前进行声明,如果不声明,也是可以的,只要函数的定义在被调用之前即可。像IAR嵌入式开发环境下,可以通过选项强制必须有函数的声明。

关于头文件与C文件,我觉得两者的区别主要是内容的不同,是我们自行约定的。对于编译器来讲,它不管你是什么,它只认文本文件,但我们约定要将全局声明放在头文件内,以方便全局声明与调用,而函数实现,一定要放在C文件里。如果放在头文件里,其实也是可以的,只是在多文件调用时,编译器会产生多个实现的报错。(当然,只调用一次,则不会产生错误。)

关于查找,文章中提到的哨兵查找的实现挺棒的,只是在嵌入式编程里,像类似的查找基本都是const表,因此,无法在最后一位写入查找的值。如果我们的查找方式是在内存里,这个查找算法在随机数排序方式下还是不错的。

函数的应用非常有学问,像文章提到的“通用性”,这个就需要编程者要有较高的抽象能力与强大的数学总结归纳能力,善于发现内部相通的地方。总之,学习是循序渐进,切不可急于求成,让浮躁加身。



院士
2018-06-03 10:30:47     打赏
12楼
第八章、动手编写各种函数


动手编写函数这一章讲得我们如何将上面几章所学知识贯穿于我们的程序中。

宏定义,我们多用于对常量的标识,将一个平凡的数字赋予清晰易懂的注释。而宏定义函数,可是有爱有恨。一方面,宏定义函数简单;另一方面,宏定义函数也有诸多副作用。在宏定义后,编译器是通过字符串替换的方式达到我们的设计要求,如果没有编译错误,肯定万事大吉;要是有错误,这个错误的定位,编译器多半会是较大偏差,给我们挖bug带来相当大的不便。

这个不便还存在于单步调试过程,如果宏定义函数只有一个语句,这个问题还较小,如果是多条语句,将无法查看此时的变量实时值,无法进行单步暂停与分析,鉴于上述几个副作用,除非原子操作,否则我是不会使用这个宏定义函数。

宏定义对于常量来说尽量书写格式统一,字节对齐,使我们的代码整洁清晰。

对于排序算法,本章仅讲了经典的冒泡算法,这个非常实用。

递归函数,看似非常好的解决斐波那切函数,我个人觉得没有应用的意义。在本人有限的编程的经验里,没有使用过递归函数解决的问题,不过,我以后也不打算使用。

缓冲与重定向,这两个的出现比较突兀,也很难理解。缓冲的作用,适用于不同处理速度的两个模块之间数据交换时使用,可以增大数据处理的稳定性。重定向,可以理解接口的再次封装,之前指向的串口通讯,现在重定向指向了USB通讯。

对于转义字符,一定要看一下,并亲自操作。这个东西只有用到的时候才知道其具体的意义。

今天就写到这里吧~~



院士
2018-06-08 00:01:34     打赏
13楼

测试题一:

解答如下:

#include <stdio.h>

/**
  * @brief   打印星符金自塔
  * @param
  * @retval
  * @date   2018-06-07
  * @note   家庭作业第一题
  */

char str0[] = "    *\n   **\n  ***\n ****\n";

int main()
{
  printf("%s", str0);
  while(1)
  {
  	;
  }
}


rst01.jpg


院士
2018-06-08 00:12:09     打赏
14楼

测试题二,解答如下:

#include <stdio.h>
#include <stdint.h>
#include <string.h>



#define NODE_SHAPE	('*')
#define BUF_LENGTH	(10)

char StrBuf[BUF_LENGTH + 1] = {0, };
const char strPrompt[] = "please input the numbers of floor\n";

/**
  * @brief   打印星符金自塔
  * @param
  * @retval
  * @date   2018-06-07
  * @note   家庭作业第二题
  */

void MakeShape(char *pBuf, uint8_t len)
{
	memset(pBuf, ' ', BUF_LENGTH - 1);
	uint8_t pos;
	if(len >= BUF_LENGTH)
	{
		pos = BUF_LENGTH - 1;
	}
	else
	{
		pos = len;
	}

	pBuf += (BUF_LENGTH - 1);
	while(pos-- > 0)
	{
		*pBuf-- = NODE_SHAPE;
	}
	pBuf[BUF_LENGTH] = '\0';
}

/**
  * @brief   依输入数量打印星符金自塔
  * @param
  * @retval
  * @date   2018-06-07
  * @note   家庭作业第二题
  */
int main()
{
	uint8_t i = 0;
	char tempInput;
	printf("%s\n", strPrompt);
	scanf("%d", &tempInput);
	printf("%d floors\n", tempInput);
	for(i = 1; i <= tempInput; i++ )
	{
		MakeShape(&StrBuf[0], i);
		printf("%s\n", StrBuf);
	}
	while(1)
	{
		;
	}
  return 0;
}


rst02.jpg


院士
2018-06-08 00:14:00     打赏
15楼

测试题目三,解答如下:


#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define BUF_LENGTH	(10)

char StrBuf[BUF_LENGTH + 1] = {0, };
const char strPrompt0[] = "please input the BCD format number:\n";
const char strPrompt1[] = "please input the BIN format number:\n";
const char strPrompt2[] = "the wrong BIN input! NEED 8 bits\n";
char InputBuf[BUF_LENGTH] = {0,};

const char BINarray[10][5] =
{
  {'0', '0', '0', '0', 0},
  {'0', '0', '0', '1', 0},
  {'0', '0', '1', '0', 0},
  {'0', '0', '1', '1', 0},
  {'0', '1', '0', '0', 0},
  {'0', '1', '0', '1', 0},
  {'0', '1', '1', '0', 0},
  {'0', '1', '1', '1', 0},
  {'1', '0', '0', '0', 0},
  {'1', '0', '0', '1', 0},
};

/**
  * @brief  BCD码转二进制
  * @param
  * @retval
  * @date   2018-06-07
  * @note
  */

void BCDtoBIN(char *pBuf, uint8_t val)
{
	uint8_t i;
	int8_t j;
	uint8_t temp;

  memset(pBuf, ' ', BUF_LENGTH - 1);

  for(j = 1; j >= 0; j--)
  {
    temp = (val >> (4 * j)) & 0x0F;
    for(i = 0; i < 4; i++)
    {
      *pBuf++ = BINarray[temp][i];
    }
    *pBuf++ = ' ';
  }
}

/**
  * @brief   二进制转换为BCD码
  * @param
  * @retval
  * @date   2018-06-07
  * @note
  */
int8_t BINtoBCD(char *pBuf, char *pVal)
{
  uint8_t len = 0, res = 0;
  int8_t i, temp, ret = 0;
  char *p = pVal;
  while(*p++)
  {
    len++;
  }

  if(len == 8)
  {
    p = pVal;
    for(i = 3; i >= 0; i--)
    {
      temp = *p++ - '0';
      temp <<= i;
      res += temp;
    }
    *pBuf++ = res + '0';
    p = pVal + 4;
    res = 0;
    for(i = 3; i >= 0; i--)
    {
      temp = *p++ - '0';
      temp <<= i;
      res += temp;
    }
    *pBuf++ = res + '0';
    *pBuf = 0;
    ret = 1;
  }
  else
  {
    ret = -1;
  }
  return (ret);

}

void main()
{
  int8_t err;
  char tempInput;
	printf("%s\n", strPrompt0);
	scanf("%d", &tempInput);
	tempInput = (tempInput / 10) * 16 + tempInput % 10;
	BCDtoBIN(&StrBuf[0], tempInput);
	printf("%s\n", StrBuf);

	printf("%s\n", strPrompt1);
	scanf("%s", &InputBuf);
	printf("%s\n", InputBuf);
	err = BINtoBCD(&StrBuf[0], &InputBuf[0]);
  if(err > 0)
  {
    printf("%s\n", StrBuf);
  }
  else
  {
    printf("%s\n", strPrompt2);
  }
	while(1)
	{
		;
	}
}

rst03.jpg


院士
2018-06-08 00:15:27     打赏
16楼

测试题目四,解答如下:


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define BUF_LENGTH  (10)

char StrBuf[BUF_LENGTH + 1] = {0, };
char InputBuf[BUF_LENGTH] = {0,};

#define BCDtoBIN(val, p) (itoa(val, p, 2))
#define BINtoBCD(ptr, r, n) do  \
                      {   \
                        for(n = 3; n >= 0; n--) \
                        {                       \
                          if(*ptr++ == '1')     \
                          {                     \
                            r |= (0x01 << n);   \
                          }                     \
                        }                       \
                      }while(0)

int main()
{
  char temp;
  signed char i;
  char res = 0;
  char BinBuf[8];
  char *p;
  scanf("%x", &temp);
  BCDtoBIN(temp, StrBuf);
  printf("%s\n", StrBuf);
  getchar();
  for(i = 0; i < 8; i++)
  {
    BinBuf[i] = getchar();
  }
  p = BinBuf;
  BINtoBCD(p, res, i);
  res *= 10;

  p += 4;
  BINtoBCD(p, res, i);
  printf("%d\n", res);

  while(1)
  {
    ;
  }

  return 0;
}

大家自行运行吧!

exp05.jpg


院士
2018-06-08 00:15:44     打赏
17楼

测试题目五,解答如下:


#include <stdio.h>
#include <stdint.h>

typedef struct _QueueZoneClass
{
  void *content;
  struct _QueueZoneClass *next;
}QueueZoneClass;

typedef struct _QueueIndexClass
{
  QueueZoneClass *head;
  uint8_t entries;
}QueueIndexClass;

QueueZoneClass QZone[10] = {0, };
QueueIndexClass *pIndex;

void QueueInit(QueueIndexClass *pIn, QueueZoneClass *pQZ)
{
  pIn->head = pQZ;
  pIn->entries = 0;
}

int8_t QueueInsert(QueueIndexClass *pIn, QueueZoneClass *pQZ, uint8_t pos)
{
  int8_t err = 0;
  uint8_t i;
  QueueZoneClass *p = pIn->head;
  if(pos > pIn->entries)
  {
    pos = pIn->entries;
  }

  for(i = 0; i < pos; i++)
  {
    p = p->next;
  }
  pQZ->next = p->next;
  p->next = pQZ;
  pIn->entries += 1;

  return (err);
}

char *str[] = {
  "John",
  "Peter",
  "Machel",
};


int main()
{
  int8_t err = 0;
  uint8_t i;
  QueueZoneClass *p;
  QZone[1].content = (char *)str[0];
  QZone[2].content = (char *)str[2];
  QZone[4].content = (char *)str[1];
  QueueInit(pIndex, &QZone[0]);
  err = QueueInsert(pIndex, &QZone[2], 0);
  err = QueueInsert(pIndex, &QZone[1], 1);
  err = QueueInsert(pIndex, &QZone[4], 2);

  p = pIndex->head->next;

  for(i = 0; i < pIndex->entries; i++)
  {
    printf("%s\n", (char *)(p->content));
    p = p->next;
  }
  while(1)
  {
    ;
  }
}

运行结果如下:

rst01.jpg



院士
2018-06-09 11:17:53     打赏
18楼

第九章、字符串

字符串的应用非常多,也非常广泛,例如我们要保存的文件名就是一个字符串。本章我们就学习字符串的知识。

字符串的本质是字符类型变量有规则的顺序存储在一起的字符数组。其有三个重要的性质:一、字符变量顺序存储,不能分开存储;二、以’\0’为结束符;三、字符串名是其存储的首地址指针;

我们再对以上三点进行深入分析:

分析一:字符串属于静态生命周期,由于其应用特性,我们一般声明于flash上,因此不能被修改。如需修改,我们需要将字符串拷贝到RAM中来。

分析二:字符串的结束判断真的很单纯,就是判断字符值是否等于’\0’,换句话说,如果我们不慎将结尾的’\0’字符修改,则字符串将一往无前的查找那个属于它的’\0’结尾符,导致我们的显示异常,程序出错。

分析三:字符串的名字就是首地址指针,所以我们引用字符串时可以直接使用其名字,当然,如果我们声明字符串数组的话也只需要再加一层中括号,如Name[5][],就可以存储5个人的名字了。

再谈一点:对于字符串的内容,我们一般多使用字母、数字或者符号,其实,它还支持转义符——原理上就是字符数组嘛,如”hello\nEEPW\n”

在操作字符串的时候,我们的依据就是上面谈到的三点,首地址,顺序存储,结尾符。

这里我们以获取字符串长度的示例来说明:


uint8_t GetStrLength(char *p)
{
	uint8_t len;
	while(*p++ != 0)
	{
		lenen++;
	}
	return (len);
}
char str[] = “www.eepw.com.cn”;
void main(void)
{
	uint8_t temp;
	temp = GetStrLength(str);
	printf(“the length of string is %d\n”, temp);
	while(1)
	{
		;
	}
}




共18条 2/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]