首页 > 其他分享 >字符指针与字符数组的复习

字符指针与字符数组的复习

时间:2023-02-16 11:47:37浏览次数:34  
标签:字符 复习 int args char num flags str 指针

遇到的刷题题目,给定sec秒,将其转换为时分秒输出,规定了函数形式为 char* timeTrans(int sec) 且需要返回修改的字符串首地址

#include <stdio.h>
char* timeTrans(int sec, char * time_str);


int main(void)
{

    char str[10];
    timeTrans(3662, str);
    // printf("Hello, World!");
    printf(str);
    printf("helloworld\n");
    return 0;
}



char* timeTrans(int sec, char *time_str)
{
    int second = sec;
    int hour = 0;
    int min = 0;
    char *str = time_str;

    //get numbers
    hour = second / 3600;
    second = second % 3600;
    min = second / 60;
    second = second % 60;
    //trans to string
    sprintf(str, "%02d:%02d:%02d", hour, min, second);
    return str;
}

在函数内部创建字符串数组来返回势必会出现函数结束时被释放的问题,暂时不论全局变量在函数种修改的操作,个人认为传参是个比较好的解决方案
而传字符串参数等等细节引发了一些问题,故进行记录
这里传入time_str形参,类型为字符串指针

首先借助C programming language的实验说明字符串指针

字符(串)指针

形如“HelloWorld”的字符串实际是字符数组常量,且以‘\0’结尾,存放在静态区,程序通过使用字符指针对其进行访问。
字符指针使用char *定义(如果我们在main函数中定义字符指针,则存储在main的栈区中),该指针仅仅是指向字符串常量,因此不可对其所指向的内容进行修改

//Fromc programming language p90
char amessage[] = "now is the time";
char *pmessage  = "now is the time";

变量 pmessage 就是一个字符串指针,指向了常量字符串 "now is the time" ,实验打印如下内容

printf("%c\n", *pmessage); // 1
printf("%s\n",  pmessage); // 2
printf("%c\n",  *(pmessage+1)); // 3
printf("%s",  (pmessage+1)); // 4

输出结果:

n                   // 1
now is the time     // 2
o                   // 3
ow is the time      // 4

说明pmessage指向的是一个字符,而这个字符会被视为字符串的首元素,因此4会打印出缺失n的字符串

字符数组

形如上面的amessage变量,就是字符数组。如果在main函数中定义字符数组,则将在栈中存储一个该长度的char数组,每个元素均可进行更改,与字符指针有本质的区别,不再多做解释,参考C programming language P90十分有帮助。

关于sprintf()函数

出现的问题在于,当使用sprintf函数时,传入的首个参数应该是什么?
虽然函数定义int sprintf(char * buf, const char *fmt, ...)中首个参数为char *类型,但是根据功能推测,函数是为了将后面的内容以合适的形式存入buf处,那么buf所指向的内容应该是一块可修改的内存,因此不能为sprintf函数传入字符指针参数,而应该传入一个字符数组。如果将代码段一中

int main(void)
{

    char str[10];
    timeTrans(3662, str);
    // printf("Hello, World!");
    printf(str);
    printf("helloworld\n");
    return 0;
}

中的char str[10];更改为char * str = "00:00:00";,就会引发程序的异常。

下面提供sprintf的实现源码,便于自己后续有空时参考

int vsprintf(char *buf, const char *fmt, va_list args)
{
	int len;
	unsigned long long num;
	int i, base;
	char * str;
	const char *s;

	int flags;		/* flags to number() */

	int field_width;	/* width of output field */
	int precision;		/* min. # of digits for integers; max
				   number of chars for from string */
	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
	                        /* 'z' support added 23/7/1999 S.H.    */
				/* 'z' changed to 'Z' --davidm 1/25/99 */


	for (str=buf ; *fmt ; ++fmt) {
		if (*fmt != '%') {
			*str++ = *fmt;
			continue;
		}

		/* process flags */
		flags = 0;
		repeat:
			++fmt;		/* this also skips first '%' */
			switch (*fmt) {
				case '-': flags |= LEFT; goto repeat;
				case '+': flags |= PLUS; goto repeat;
				case ' ': flags |= SPACE; goto repeat;
				case '#': flags |= SPECIAL; goto repeat;
				case '0': flags |= ZEROPAD; goto repeat;
				}

		/* get field width */
		field_width = -1;
		if ('0' <= *fmt && *fmt <= '9')
			field_width = skip_atoi(&fmt);
		else if (*fmt == '*') {
			++fmt;
			/* it's the next argument */
			field_width = va_arg(args, int);
			if (field_width < 0) {
				field_width = -field_width;
				flags |= LEFT;
			}
		}

		/* get the precision */
		precision = -1;
		if (*fmt == '.') {
			++fmt;
			if ('0' <= *fmt && *fmt <= '9')
				precision = skip_atoi(&fmt);
			else if (*fmt == '*') {
				++fmt;
				/* it's the next argument */
				precision = va_arg(args, int);
			}
			if (precision < 0)
				precision = 0;
		}

		/* get the conversion qualifier */
		qualifier = -1;
		if (*fmt == 'l' && *(fmt + 1) == 'l') {
			qualifier = 'q';
			fmt += 2;
		} else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L'
			|| *fmt == 'Z') {
			qualifier = *fmt;
			++fmt;
		}

		/* default base */
		base = 10;

		switch (*fmt) {
		case 'c':
			if (!(flags & LEFT))
				while (--field_width > 0)
					*str++ = ' ';
			*str++ = (unsigned char) va_arg(args, int);
			while (--field_width > 0)
				*str++ = ' ';
			continue;

		case 's':
			s = va_arg(args, char *);
			if (!s)
				s = "<NULL>";

			len = strnlen(s, precision);

			if (!(flags & LEFT))
				while (len < field_width--)
					*str++ = ' ';
			for (i = 0; i < len; ++i)
				*str++ = *s++;
			while (len < field_width--)
				*str++ = ' ';
			continue;

		case 'p':
			if (field_width == -1) {
				field_width = 2*sizeof(void *);
				flags |= ZEROPAD;
			}
			str = number(str,
				(unsigned long) va_arg(args, void *), 16,
				field_width, precision, flags);
			continue;


		case 'n':
			if (qualifier == 'l') {
				long * ip = va_arg(args, long *);
				*ip = (str - buf);
			} else if (qualifier == 'Z') {
				size_t * ip = va_arg(args, size_t *);
				*ip = (str - buf);
			} else {
				int * ip = va_arg(args, int *);
				*ip = (str - buf);
			}
			continue;

		case '%':
			*str++ = '%';
			continue;

		/* integer number formats - set up the flags and "break" */
		case 'o':
			base = 8;
			break;

		case 'X':
			flags |= LARGE;
		case 'x':
			base = 16;
			break;

		case 'd':
		case 'i':
			flags |= SIGN;
		case 'u':
			break;

		default:
			*str++ = '%';
			if (*fmt)
				*str++ = *fmt;
			else
				--fmt;
			continue;
		}
		if (qualifier == 'l') {
			num = va_arg(args, unsigned long);
			if (flags & SIGN)
				num = (signed long) num;
		} else if (qualifier == 'q') {
			num = va_arg(args, unsigned long long);
			if (flags & SIGN)
				num = (signed long long) num;
		} else if (qualifier == 'Z') {
			num = va_arg(args, size_t);
		} else if (qualifier == 'h') {
			num = (unsigned short) va_arg(args, int);
			if (flags & SIGN)
				num = (signed short) num;
		} else {
			num = va_arg(args, unsigned int);
			if (flags & SIGN)
				num = (signed int) num;
		}
		str = number(str, num, base, field_width, precision, flags);
	}
	*str = '\0';
	return str-buf;
}

int sprintf(char * buf, const char *fmt, ...)
{
	va_list args;
	int i;

	va_start(args, fmt);
	i=vsprintf(buf,fmt,args);
	va_end(args);
	return i;
}
// copy from stdio.c

(recommend referring to C programming language P90)

标签:字符,复习,int,args,char,num,flags,str,指针
From: https://www.cnblogs.com/Willard-Wong/p/17126108.html

相关文章

  • 《判断字符串是IP还是域名》
    首先假设输入字符串为域名,然后检查输入字符串是否是一个合法的IPv4地址。如果不是,则将输入字符串解析为域名,并输出结果。如果是一个合法的IPv4地址,则直接输出结果。注......
  • java字符串之间的拼接方法
    在java开发中,有很多时候,需要把一个集合或者数组中的数据进行拼接,拼接成一个全新格式的字符串,这时候就用到了java中的一些方法,方法如下:一、Joiner-guava点击查看代码/......
  • Windows命令findstr文本文件中查找字符串(findstr-对应于Linux中的grep命令)
    一、实例如查找coco.names文件中的car所在的行:findstr/N/A:02carcoco.names或将全部内容(用点.代替)转出到文本文件:findstr/N/A:02.coco.names>coco.txt二、知识点......
  • 2.16 字符与入口程序
    1.ascll码7位或8位来表示一个字母同时第八位为1为扩展ascll码我们也能用扩展ascll码表示汉字2.GB23123.sacll码问题由于扩展码不统一,每个国家都有一套标准,所以会乱码......
  • 力扣3. 无重复字符的最长子串
    给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1:输入:s="abcabcbb"输出:3解释:因为无重复字符的最长子串是"abc",所以其长度......
  • acwing 我在哪?(字符串哈希)
    原题链接题解分析设答案为ans,那么大于ans,肯定不成立,小于ans成立,这符合二分答案的特点然后使用unordered_set和substr进行查重substr:第一个参数为开始项,第二个参数......
  • 字符串类型
    字符串操作vars,s1,s2:String;begins:='microsoftisabigCompany';s2:=Trimleft(s);//s2的内容为'microsoftisabigCompany's2:=TrimRig......
  • 力扣---3. 无重复字符的最长子串
    给定一个字符串s,请你找出其中不含有重复字符的最长子串的长度。示例1:输入:s="abcabcbb"输出:3解释:因为无重复字符的最长子串是"abc",所以其长度为3。示例2:......
  • 字符串方法
    >>>spam='Helloworld'>>>spam.upper()#所有字母被转为大写'HELLOWORLD'>>>spam.lower()#所有字母被转为小写'helloworld'>>>spam#未改变原字符串'......
  • c/c++ pta判断和选择 (复习)
     ......