嵌入式C语言杂七杂八

文章介绍了C语言中处理文件的fgets和fgetc函数,字符串逆序操作,结构体与函数指针的使用,以及日志记录的宏定义方法。同时,展示了从文本中提取配置信息和使用sscanf函数的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

fget函数的用法

fgets() 函数用来从指定的文件中读取一个字符串,并保存到字符数组中。

str 为字符数组,n 为要读取的字符数目,fp 为文件指针。

char *fgets(char *str, int n, FILE *stream)

返回值:读取成功时返回字符数组首地址,也即 str;读取失败时返回 NULL;如果开始读取时文件内部指针已经指向了文件末尾,那么将读取不到任何字符,也返回 NULL。

返回值

如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。

如果发生错误,返回一个空指针。

#include <stdio.h>
#include <stdlib.h>
#define N 100
int main()
{   
    FILE *p;
    char str[N + 1] = {0};
    p = fopen("a.txt",  "r");
    if (p == NULL) {
        printf("open file faild \n");
    }
    while ((fgets(str, N, p)) != NULL) {
            printf("%s", str);
    }

    fclose(p);

    return 0;
}
  

fgetc函数的用法

fgetc 是 file get char 的缩写,意思是从指定的文件中读取一个字符。

fgetc() 的用法为:int fgetc (FILE *fp);

fp 为文件指针。fgetc() 读取成功时返回读取到的字符,读取到文件末尾或读取失败时返回EOF。

EOF 是 end of file 的缩写,表示文件末尾,是在 stdio.h 中定义的宏,它的值是一个负数,往往是 -1。fgetc() 的返回值类型之所以为 int,就是为了容纳这个负数(char不能是负数)。

表示从a.txt文件中读取一个字符,并保存到变量 ch 中

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

int main()
{
    FILE *fp;
    char ch;
   
    //如果文件不存在,给出提示并退出
    if( (fp=fopen("a.txt", "r")) == NULL ){
        puts("Fail to open file!");
        exit(0);
    }
    //每次读取一个字节,直到读取完毕
    while((ch = fgetc(fp)) != EOF ) {
        putchar(ch);
    }

    fclose(fp);

    return 0;
}

一道简单的字符串题目,就是单词逆序,不是完全字符串完全逆序

上面是输入

abc  def  123   456

下面是输出

cba  fed  321   654

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

/*实现思路: 例如 abc word, 先找到空格,然后逆序就得到cba,word没有空格,
就找到空格后的第一个字符,和最后一个字符,逆序就得到drow */

int main(int argc, char *argv[])
{
    char str[100] = {0};
    int len = 0;
    int len2 = 0;
    gets(str);  /* 输入字符串*/
    len = strlen(str); /* 计算总的字符串的长度 */
    for (int i = 0; i < len; i++) { /* 遍历字符串中的字符 */
         if (str[i] == ' ') { /* 如果找到了空格 */
             for (int  j = i - 1;  j >= len2; j--) { /* 找到来空格, i-1得到单词的最后一个字符,然后逆序输入(j--) */
                  printf("%c", str[j]);
             }
             printf(" ");
             len2 = i + 1; /* 得到了最后一个单词的第一个字符 */
         }       
         if (i == len - 1) { /* 如果遍历到了最后一个单词的最后一个字符的时候 */
             for (int j = i; j >= len2; j--) { /* 逆序输入最后一个单词 */
                  printf("%c", str[j]);
             }
         }        
    }
    printf("\n");
} 

运行结果如下:

C语言结构体函数指针
#include <stdio.h>
#include <malloc.h>
typedef struct Value  //只有结构体变量才分配地址,而结构体的定义是不分配空间的
{
	int dat;
	char str;
}Value;

typedef struct Fun{	  //只有结构体变量才分配地址,而结构体的定义是不分配空间的
	int a,b;
	int m,n;
	void(*print)(void);			//函数指针,是一个指针变量,指向某个函数的地址,
	int (*add)(int a,int b);    //即可实现该函数的功能.
	int (*returnVal)(void);
	void(*test)(int m,int n);
}Fun;
/*****************************************************/
void print(void)
{
	printf("Print success!\n");
}

int add(int a,int b)
{
	return a+b;
}
int returnVal(void)
{
	return 1024;
}
void TEST(int j,int k)
{
	printf("TEST():%d\n",j+k);
}

/****初始化一个结构体变量****/
Fun f = {
	.a = 1,
	.b = 5,
	.m = 10,
	.print = print,
	.add = add,
	.returnVal = returnVal,
	.test = TEST				//将结构体test函数地址,指向TEST真正存在的函数
};
/*****************************/
int main(void)
{	
	Value *va = (Value*)malloc(sizeof(Value));	//初始化一个Value结构体的变量
	Fun   *t  = (Fun*)malloc(sizeof(Fun));      
	t->n  = 13;								//等价于t->n = 13;
	va->dat = 12;
	printf("va->dat:%d\n",va->dat);
	printf("t->n:%d\n",t->n);
	print();						
	printf("%d\n",f.add(f.a,f.b));
	printf("%d\n",f.returnVal());
	f.test(f.m,18);		//传入参数既可以是结构体变量f里的值,也可以外部输入
	TEST(50,100);   
	return 0;
}

运行结果:

C语言日志

#define DEBUG1(format,args...) do { \
    printf("%d  %s  "format, __LINE__, __func__, ##args);\
} while(0)


#define DEBUG(format, ...)  do { \
    printf("%s(%d):", __func__, __LINE__); \
    printf(format, ##__VA_ARGS__);         \
    printf("\r\n");                        \
} while (0)

更加完整的一个日志函数

#include <stdio.h>

#define Print(x, y) do { \
    printf("%d\n", x); \
    printf("%d\n", y); \
} while(0)

int   dbg_level = 1; 
#define LAN_HOST_TRACE_FLAG  1
#define DEBUG_TRACE(x, y) do { \
    if ( dbg_level&(x) ) { \
    printf("[hostinfo]:"); \
    printf y; \
    fflush(stdout);} \
} while(0)


int main() 
{
    int interval = 1;

    DEBUG_TRACE(LAN_HOST_TRACE_FLAG, ("[%s %d]:interval = %d.\n", __func__, __LINE__, interval));
    
    return 0;
}

一个小demo需求:提取uci命令(uci show  wireless.default_radio0)里面的ssid,加密,以及密码,把内容copy到txt文件调试,实现后在虚拟机效果一样。

txt文本内容:

wireless.default_radio0=wifi-iface
wireless.default_radio0.device='radio0'
wireless.default_radio0.network='lan'
wireless.default_radio0.mode='ap'
wireless.default_radio0.ssid='Hiwooya'
wireless.default_radio0.encryption='psk2'
wireless.default_radio0.key='1234567890'

C语言代码如下:

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

// 定义一个结构体来存储配置信息
struct wireless_config {
    char ssid[128];
    char encryption[128];
    char key[128];
};

// 函数:从字符串中提取值
int extract_value(const char *line, char *value, int value_size) 
{ 
    //strchr`函数用于在一个字符串中查找第一次出现的指定字符,并返回从该字符到字符串结束的所有字符的指针。
    //如果未找到指定字符,函数返回`NULL`
    const char *start = strchr(line, '\'');
    const char *end = NULL;
    int len = 0;

    if (start != NULL) {
        start++;
        end = strchr(start, '\''); 
        if (end != NULL) {
            len = end - start; //计算得到`start`和`end`之间的距离,这个距离正是被引号包围的文本的长度。
            //在C语言中,两个指针相减的结果是它们之间相差的元素个数,
            //因此这里的`len`代表了两个单引号之间字符的数量。
            if (len < value_size) {
                strncpy(value, start, len);
                value[len] = '\0';
                return 1;
            }
        }

    }

    return 0; // 未提取值
}

// 主函数
int main() 
{
    FILE *file = NULL;
    char line[256] = {0};
    struct wireless_config config = {0}; // 初始化结构体

    // 打开文件
    file = fopen("123.txt", "r");
    if (!file) {
        perror("Failed to open file");
        return EXIT_FAILURE;
    }

    // 逐行读取文件内容
    while (fgets(line, sizeof(line), file)) {
        if (strstr(line, "wireless.default_radio0.ssid=")) {
            extract_value(line, config.ssid, sizeof(config.ssid));
        } else if (strstr(line, "wireless.default_radio0.encryption=")) {
            extract_value(line, config.encryption, sizeof(config.encryption));
        } else if (strstr(line, "wireless.default_radio0.key=")) {
            extract_value(line, config.key, sizeof(config.key));
        }
    }

    // 关闭文件
    fclose(file);

    // 显示提取的配置信息
    printf("SSID: %s\n", config.ssid);
    printf("Encryption: %s\n", config.encryption);
    printf("Key: %s\n", config.key);

    return 0;
}

运行效果:

sscanf函数的用法

sscanf()` 函数是 C 标准库 `<stdio.h>` 中的一个函数,用于从字符串中按照指定的格式读取数据,类似于 `scanf()` 函数,但 `sscanf()` 从字符串中读取数据,而不是从标准输入(键盘)读取。

int sscanf(const char *str, const char *format, ...);

- `str`:要读取数据的字符串。
- `format`:格式字符串,指定了要读取的数据的类型和格式,就像 `scanf()` 中的格式字符串一样。
- `...`:要读取的数据存储位置,与 `scanf()` 类似,可以是各种类型的指针。

`sscanf()` 函数会尝试根据指定的格式从字符串 `str` 中读取数据,并将读取到的数据存储到提供的位置中。它的返回值是成功匹配并读取的参数个数,如果没有匹配成功,则返回值为 0。

#include <stdio.h>

int main() 
{
    char str[] = "Hello 123 45.67";
    char word[10];
    int num1, num2;
    float num3;

    // 从字符串中读取数据
    int count = sscanf(str, "%s %d %f", word, &num1, &num3);

    // 打印读取的数据
    printf("Read %d items:\n", count);
    printf("Word: %s\n", word);
    printf("Integer: %d\n", num1);
    printf("Float: %f\n", num3);

    return 0;
}

运行效果:

实际遇到情况,需要提取部分参数,那么如何跳过部分参数。

我们现在只需要提取ip flag  address device, 那么如何实现呢

我们只需要在%s中间加上*号,就可以跳过,如何还要跳过前面的部分,如0x2,只需要2,在格式化格式前面加上0x。如再遇到sscanf函数,忘记怎么用,跑一下下面的Demo即可。

#include <stdio.h>


int main(int argc, char *argv[]) 
{
    FILE *fp = NULL;
    char line[256] = {0};
    char mac_str[18] = {0}, ip_str[16] = {0}, dev_name[6 + 1] = {0};
	int arg_num = 0;
	unsigned int flag = 0;


    fp = fopen("/proc/net/arp", "r");
    if (fp == NULL) {
        printf("fopen open faild\n");
        return 0;
    }
    while (fgets(line, sizeof(line), fp)) {
        //IP address       HW type     Flags       HW address            Mask     Device
		//192.168.1.1      0x1         0x2         00:11:22:33:44:55     *        eth0
        arg_num = sscanf(line, "%s 0x%*x 0x%x %s %*s %s", ip_str, &flag, mac_str, dev_name);
        if (arg_num == 4) {
            printf("ip:%s flags:%x address:%s device:%s\n", ip_str, flag, mac_str, dev_name);
        }
    }

    fclose(fp);

    return 0;
}

运行效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值