首页 > 其他分享 >C-字符串

C-字符串

时间:2023-09-06 15:25:53浏览次数:31  
标签:const int char str printf 字符串 输入

一、字符串

字符:人能看得懂的符号或图案,在内存中以整数形式存储,根据ASCII码表中的对应关系显示出相应的符号或图案

'\0'     0   空字符
 '0'     48
 'A'     65
 'a'     97   

:是一种数据结构,存储类型相同的若干个数据

对于串型结构的处理是批量性的,会从头开始直到遇到结束标志(可自定义,一般取极大的数,即~0)停止

字符串:由字符组成的串型结构,结束标志是 '\0'

二、字符串的存在形式

1、字符数组:

char str[10] = {'a','b','c',...};        

由char组成的数组,注意要为'\0'预留位置,初始化麻烦

char str[5] = {'a','b','c','d','e'};
cahr str1[5]= {'A','B','C','D','E'};
str[0] = 'A';    //可以修改
printf("%s\n",str);    //abcdeABCDE
没有结束标识符,即没有为'\0'预留位置,且申请的为栈内存

使用的是栈内存,数据可以修改

2、字符串字面值:

"由双引号包含的若干个字符"       
"hehe"

末尾会隐藏一个'\0',定义也方便

字符串字面值就是以地址形式存在的,是常量,数据存储在代码段中,不能修改,否则段错误

printf("%s","hello world!");    //末尾自动隐藏'\0',%s需要提供地址

    char* p1 = "hello";
//    p[0] = 'H';    不能修改,说明不是栈内存
    char* p2 = "hello";    //p1、p2地址相同

    char str[] = "hello";
    str[0] = 'H';
    printf("%s\n",str);      //Hello
    printf("%p %p %d %d %d\n",p1,p2,sizeof("hellooo"),sizeof(p1),sizeof(str));    //0x80485f0 0x80485f0 8 4 6

注意:相同内容的多份字符串字面值,在代码段中只会存在一份

注意:sizeof("xxxx") 计算出 字符个数+1(计算了'\0')

3、常用方式:

字符数组[] = "字符串字面值";        

会自动为'\0'预留位置

注意:赋值完成后,该字符串在内存中有两份,一份在代码段,另一份在栈内存(可修改)

三、字符串的输入和输出

输入scanf/gets/fgets

  • scanf
scanf %s 地址

缺点:不能输入空格

遇到空格/回车/Tab键认为输入结束,但是空格/回车/Tab键仍会留在输入的缓冲区中。常见的是使用getchar(),处理scanf的后事;如果想要清除残余,可以使用fllush()清除缓存。

  • gets
char *gets(char *s);
功能:输入字符串到s中 能够输入空格
返回值:s   

链式调用

缺点:有警告,输入的长度不受限制,有风险

可以接收空格/回车/Tab键回车结束输入,(会丢弃换行符)但是在Linux中gets是一个危险的函数,因为没有溢出检查回车键不会留在输入缓冲区中。

  • fgets
char *fgets(char *s, int size, FILE *stream);
功能:输入长度最多为 size-1 的字符串,会自动为'\0'预留位置

printf("%s\n",fgets(str,10,stdin));   

超出部分不接收,不足时最后的'\n'也会一起接收,回车结束输入

输出printf/puts

  • printf
printf %s 地址
  • puts
int puts(const char *s);
功能:输出一个字符串,并且会自动在末尾打印一个'\n'
返回值:成功输出的字符个数    

练习1:实现一个函数,判断一个字符串是否是回文串,如"abccba"

#include <stdio.h>
#include <stdbool.h>

bool is_huiwen(const char* str)
{
    size_t len = 0;
    while(str[len]) len++;     //计算字符串长度

    for(int i=0; i<len/2; i++)
    {
        if(str[i] != str[len-i-1]) return false;
    }
    return true;
}
int main(int argc,const char* argv[])
{
    char str[100] = {};
//    scanf("%s",str);
    printf("%d\n",is_huiwen(fgets(str));
}


四、缓冲区机制

1、输出缓冲区

缓冲区机制可以提高数据的读写速度,还可以让低速的设备与高速的CPU之间协调工作

程序要显示的数据并不会立即显示到屏幕上,而是先存储到输出缓冲区中,当满足一定条件时才会从输出缓冲区显示到屏幕上

①、遇到'\n',缓冲区中\n前的所有内容都被输出

printf("hello world!");
for(;;)     //无法输出

printf("hello world!\n");
for(;;)      //输出hello world!

printf("hello world!");
printf("hello world!");
printf("hello\n world!");
for(;;)     //输出hello world!hello world!hello 

②、遇到输入语句

printf("hello world!");
printf("hello world!");
scanf("%*c");     //从键盘读取任意字符并丢弃
printf("hello world!");
for(;;);     //输出hello world!hello world!

③、当缓冲区满了4k

④、程序正常结束时 (return语句)

⑤、fflush(stdout); 手动刷新输出缓冲区,头文件stdio

2、输入缓冲区

程序中输入的数据并不会立即从键盘接收到变量中,而是当按下回车后先存储到输入缓冲区中,然后再从缓冲区中读取到变量内存

读取失败原因1

情况1:需要输入的是整型\浮点型时,而缓冲区中的数据是字符型或符号时,此时读取会失败,并且该数据会继续残留在输入缓冲区中,会继续影响剩下的输入

int a=0,b=0,c=0;
int ret = scanf("%d%d%d",&a,&b,&c);
printf("%d %d %d ret=%d\n",a,b,c,ret);
当键盘输入为a 5 1时,输出为0 0 0 ret=0

解决:根据scanf的返回值判断输入是否有问题,如果读取失败,则先清理输入缓冲区后重新输入,直到读取成功为止

while(3 != scanf("%d%d%d",&a,&b,&c))
    {
        printf("请重新输入:");    
        stdin->_IO_read_ptr = stdin->_IO_read_end;
    }

读取失败原因2

情况2:通过fgets可以指定读取size-1个字符,但是如果输入超过size-1那么字符会残留在输入缓冲区中,继续影响接下来的输入

char str1[5] = {};
char str2[5] = {};
fgets(str1,5,stdin);
printf("%s ",str1);
fgets(str2,5,stdin);
printf("%s ",str2);
当输入为aaaabbbbhkhohof(回车)时,输出为aaaa bbbb
  • 解决方法1:(判断字符串最后一个是否是'\n')
scanf("%*[^\n]");     //从缓冲区中读取任意类型数据并丢弃,直到遇到'\n'停止
scanf("%*c");     //从缓冲区中读取任意字符类型数据并丢弃
fgets(str1,5,stdin);
scanf("%*[^\n]"); 
scanf("%*c");
printf("%s ",str1);
fgets(str2,5,stdin);
printf("%s ",str2);
//但当str1输入长度短于5就回车时,回车符会存在str1数组中,需要等待下一个回车符的出现才会输出str1
  • 方法2:
stdin->_IO_read_ptr = stdin->_IO_read_end;     //  把输入缓冲区的位置指针从当前位置,移动到末尾,相当于清理输入缓冲区       

注意:只能在Linux系统下使用

读取失败原因3

情况3:当先输入整型或浮点型,再输入字符型时,输入完整型或浮点型后按下的回车或空格,会残留在输入缓冲区,刚好被后面的字符型接收,影响输入

char str[100] = {};
int num = 0;
char ch = 0;
scanf("%d%c",&num,&ch);
printf("---%d---%c---\n",num,ch);
输入:18 a
输出:---18--- ---

解决:在%c或者gets()前面加空格

scanf("%d %c",&num,&ch);  

scanf("%d",&num);
scanf(" %c",&ch);  

scanf("%d ",&num);
gets(str);    

五、字符串相关函数

  • strlen
#include <string.h>
size_t strlen(const char *s);
功能:计算字符串的长度,不包括'\0'    

strlen有效字符个数,sizeof字节长度(内存长度)

  • strcpy =
char *strcpy(char *dest, const char *src);
功能:把src拷贝给dest,相当于给dest赋值 =
返回值:dest的首地址,链式调用    
  • strcat +=
char *strcat(char *dest, const char *src);
功能:把src追加到dest的末尾 相当于+=
返回值:dest的首地址,链式调用
  • strcmp
int strcmp(const char *s1, const char *s2);
    功能:比较两个字符串,根据字典序,谁出现早谁小,一旦比较出结果就立即返回
    返回值:
    s1 > s2 正数
    s1 == s2 0
    s1 < s2 负数
  • strncpy/strncat/strcmp
char *strncpy(char *dest, const char *src, size_t n);
char *strncat(char *dest, const char *src, size_t n);
int strncmp(const char *s1, const char *s2, size_t n);   
  • atoi
int atoi(const char *nptr);
功能:把字符串转换成int类型   
  • atof
double atof(const char *nptr);
功能:把字符串转换成double类型    
  • strstr
char *strstr(const char *haystack,const char *needle);
功能:在haystack中查找是否存在子串needle
返回值:needle在haystack中第一次出现的位置,如果找不到返回NULL   
  • sprintf
int sprintf(char *str, const char *format, ...);
功能:把各种类型的数据转换成字符串并输入到str中    

实例:

    int num = 10086;
    double d = 3.14;
    char str[100] = {};
    sprintf(str,"num=%d d=%lf\n",num,d);
    printf("%s",str);   // num=10086 f=3.140000 
    printf("%d",str[4]);     //49
  • sscanf
int sscanf(const char *str, const char *format, ...);
功能:从字符串中解析出各种类型的数据,并存储到对应的变量中    

实例:

  const char* str = "1998 12 3.14";
    int year = 0,month = 0;
    double d = 0;

    sscanf(str,"%d %d %lf",&year,&month,&d);
    printf("%d %d %lf\n",year,month,d);
  • memcpy
void *memcpy(void *dest, const void *src, size_t n);
功能:把src内存的数据拷贝n个字节到dest中   

练习1:重新实现strlen\strcpy\strcat\strcmp四个函数

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

size_t str_len(const char* str)
{
//    if(NULL == str) return 0;
    assert(NULL != str);
    const char* temp = str;
    while(*temp) temp++;
    return temp - str;
}

char* str_cpy(char* dest,const char* src)
{
    if(NULL == dest || NULL == src) return NULL;
    char* temp = dest;
    while(*temp++ = *src++);
    return dest;
}

char* str_cat(char* dest,const char* src)
{
    char* temp = dest;
    while(*temp) temp++;
    while(*temp++ = *src++);
    return dest;
}

int str_cmp(const char* s1,const char* s2)
{
    while(*s1 && *s1 == *s2) s1++,s2++;
    return *s1 - *s2;
    /*
    if(*s1 > *s2) return 1;
    if(*s1 < *s2) return -1;
    return 0;
    */
}

int main(int argc,const char* argv[])
{
    char str[256] = "hehehahaxixi";
    char* p = NULL;
    strcpy(p,str);
    printf("str_len:%d\n",str_len("hahaxixi"));
    printf("str_cpy:%s\n",str_cpy(str,"ooo"));
    printf("str_cat:%s\n",str_cat(str,"aaa"));
    printf("str_cmp:%d\n",str_cmp("aba","aba"));
}    

练习2:定义一个函数,把一个由数字字符组成的字符串转换成整数

#include <stdio.h>

int str_to_int(const char* str)
{
    int num = 0;
    while(*str && '0' <= *str && '9' >= *str)
    {
        num = num*10 + *str - '0';
        str++;
    }
    return num;
}

int main(int argc,const char* argv[])
{
    char str[256] = {};
    scanf("%s",str);
    printf("%d\n",str_to_int(str)*10);
}

练习3:定义一个函数,把一个字符串逆序

"abcd"

"dcba"

#include <stdio.h>

char* reverse_str(char* str)
{
	size_t len = 0;
	while(str[len]) len++;
	for(int i=0; i<len/2; i++)
	{
		char ch = str[i];
		str[i] = str[len-1-i];
		str[len-i-1] = ch;
	}
	return str;
}

int main(int argc,const char* argv[])
{
	char str[256] = "123456";
	printf("%s\n",reverse_str(str));
}

标签:const,int,char,str,printf,字符串,输入
From: https://www.cnblogs.com/ljf-0804/p/17682342.html

相关文章

  • 剑指 Offer 20. 表示数值的字符串
    说实话本题虽然不难,但是对边界问题的处理超乎想象(一不小心就越界访问),”简单“的难度还是说明博主本身太菜了。本题的主要考点是双指针以及对标准库(对c++来说)一些函数的运用。处理的中心思想是:先将整个字符串反转,而后再通过双指针提取其中的各个单词,而后再将其反转。这样的处理......
  • 在 PHP 数组中的两个字符串之间切换
    在PHP中,你可以使用array_flip()函数和条件语句来在数组中的两个字符串之间进行切换。以下是一个示例://创建一个数组,包含两个字符串的映射关系$mapping=array('string1'=>'value1','string2'=>'value2');//定义当前需要切换的字符串$currentString='string......
  • 找质数(图算法)、交错字符串(字符串、动态规划)、有效数字(字符串)
    找质数(图算法)找出大于200的最小的质数解答:importjava.util.*;importjava.lang.*;importjava.io.*;classIdeone{publicstaticvoidmain(String[]args)throwsjava.lang.Exception{intn=201;while(true){booleanb=tru......
  • sqlserver中怎么将一列数据拼接成一个字符串
     SELECTb.name+','FROM dbo.TechnologyColorajoin[dbo].[CustomColor]b ona.customcolorid=b.id WHEREProductId=345882800324677FORxmlPATH('')SELECT需要合并的字段+','FROM表名FORXMLPATH(''......
  • 模板字符串
    点击查看代码functionrender(template,data){constreg=/\{\{(\w+)\}\}/;//模板字符串正则if(reg.test(template)){//判断模板⾥是否有模板字符串constname=reg.exec(template)[1];//查找当前模板⾥第⼀个模板字符串的字段template=template.replace(reg,......
  • 字符串的复制
    classString{private:char*m_Buffer;unsignedintm_Size;public:String(constchar*string){//首先constchar*等同于stringm_Size=int(strlen(string));//因为64位的strlen是unisignedlongm_Buffer=newchar[m_Si......
  • 字符串处理
    1.数组拼接坑比用例322,5,6,7,,,9,5,71,7,4,3,,4importjava.util.Scanner;importjava.util.*;//注意类名必须为Main,不要有任何packagexxx信息publicclassMain{publicstaticvoidmain(String[]args){Scannerin=newScanner(System.in)......
  • LeetCode -- 394. 字符串解码(栈处理字符串问题)
     我们用栈同时维护当前字符串和倍数以及要加倍的字符串当遇到"["时,我们保存当前字符串,即将当前字符cres串入栈;当遇到"]"时,res=cres+倍数*应加倍的字符串classSolution:defdecodeString(self,s:str)->str:stack,res,multi=[],"",0......
  • 【群答疑】jmeter关联获取上一个请求返回的字符串,分割后保存到数组,把数组元素依次作为
    一个非常不错的问题,来检验下自己jmeter基本功 可能有同学没看懂题,这里再解释一下,上面问题需求是:jmeter关联获取上一个请求返回的字符串,分割后保存到数组,把数组元素依次作为下一个请求的入参 建议先自己思考,如果2小时没做出来,可以参考文末评论区的实现思路(仅登录后可见) ......
  • java 将长字符串截取为指定位数短字符代码
    //原始长字符串strContextStringstrContext="长字符串................................";ArrayList<String>arrayList=newArrayList(5);inttotalNo=strContext.length();//小字符串长度pageSizeintpageSize=20;if(totalNo>pageSize){//取模等于0,说......