C语言学习笔记4---数组、字符串

文章目录

  • 数组
    • 一维数组
    • 二维数组
    • 传参为数组
    • 数组与指针的关系
  • 字符串
    • 字符串的初始化
    • 字符串的输出
    • 字符串操作函数【注:待补充】
    • 字符串数组
  • 重要链接
  • 参考文献

数组

数组用于存储一系列具有相同数据类型的变量。数组内的元素具有连续的内存位置。

一维数组

一维数组的声明

声明一个数组时,必须要指明数组的数据类型type, 数组的长度。长度需为大于0的整数, 数组的长度用中括号包裹。

代码语法为:

type 数组名[数组的长度,即元素个数];

一维数组的初始化

初始化一维数组,若需初始化的数组已事先声明过,则直接将用大括号包裹的数组元素赋值给该数组。若事先并未声明,则在初始化是需要指明数组的数据类型。声明与初始化数组同时进行时,方括号内的数组长度可忽略,直接默认为初始化的数组元素的个数。如 int a[] = {0,0,0,3, 0, 5,0,0}.

代码语法为:

type 数组名[数组长度] = {元素1, 元素2, 元素3,…元素n};

若为稀疏数组且需要经常性更新数组元素,即数组的长度可能不能完全确定,如a[] = {0,0,0,3, 0, 5,0,0},后期还需要添加元素,可写为:

a[] = {[3]=3, [5] = 5}

遍历时,数组的长度可写为sizeof(a)/sizeof(a[0])

for(int i = 0; i < sizeof(a)/sizeof(a[0]);i++){
        printf("%d", a[i]);
        }

  1. 初始化时数组的长度并不是必须要写的,若中括号内不写数组长度,则默认数组的长度即为元素的个数。若中括号内写了数组长度, 则后面大括号中的元素个数不可超过中括号中所写的数组长度。
  2. 数组变量本身不能被赋值。如果要把一个数组中的内容全部传输给另外一个数组,只能通过遍历。
  3. 若函数的参数是数组时,需要传入数组的长度,否则无法做运算。

一维数组的索引

索引值从0即基索引至数组长度减1。数组中的元素可以通过数组名与索引值来访问。

代码实例

#include 
 
int main ()
{
   int n[ 10 ]; /* n 是一个包含 10 个整数的数组 */
   int i,j;
 
   /* 初始化数组元素 */         
   for ( i = 0; i < 10; i++ )
   {
      n[ i ] = i + 100; /* 设置元素 i 为 i + 100 */
   }
   
   /* 输出数组中每个元素的值 */
   for (j = 0; j < 10; j++ )
   {
      printf("Element[%d] = %d\n", j, n[j] );
   }
 
   return 0;
}

二维数组

多维数组的声明同一维数组一样也需要指明数据类型,每一个维度上的长度也需要用中括号来包裹说明。是几维数组就需要几个中括号。代码语法为:

type 多维数组名[size1][size2][size3]…[size n];

多维数组中最简单的形式是二维数组,本质上是一个元素为一维数组的列表。其声明与初始化规则同一维数组,代码语法分别为:

type 数组名[行数][列数];

type 数组名[行数][列数] = {{第一行的一维数组元素},{第二行的一维数组元素},…{第n行的一维数组元素}};

二维数组的索引也需要从两个维度来看,行列索引分别都是从基索引0至行数减1与列数减1.

代码实例

#include 
 
int main ()
{
   /* 一个带有 5 行 2 列的数组 */
   int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6},{4,8}};
   int i, j;
 
   /* 输出数组中每个元素的值 */
   for ( i = 0; i < 5; i++ )
   {
      for ( j = 0; j < 2; j++ )
      {
         printf("a[%d][%d] = %d\n", i,j, a[i][j] );
      }
   }
   return 0;
}

传参为数组

函数参数表中的数组实际为指针,所以无法得到该数组中元素的个数。sizeof(数组名)==sizeof(数据类型*),同时指针可以用数组的运算符[]进行运算。如

  • int sum(int *ar, int n); 与 int sum(int ar[], int n)等价
    • 以下四种函数原型是等价的:
      int sum(int *ar, int n);%数组写为指针的形式
      int sum(int *, int); %忽略数组名与变量名
      int sum(int ar[], int n);%参数为数组形式
      int sum(int [], int);%忽略参数中数组的名称与变量名称

传入函数的数组成了什么? 如如下代码段

int  isPrime(int x, int knownPrimes[], int numberOfKnownPrimes)
{
	int ret =1;
	int i;
	for(i=0; i

数组与指针的关系

数组变量为特殊的指针

  • 数组变量本身表达地址,所以定义指向数组的指针时无需用&取地址,a==&a[0]int a[10]; int *p=a; 但是数组的单元表达的是变量,需要用&取地址。
  • []运算符可以对数组做,也可以对指针做
  • *运算符可以对指针做,也可以对数组做,如*a=25
  • 数组变量为const的指针,所以不能被赋值,所以数组变量之间不能相互赋值。即int a[] 等价于int * const a

字符串

在C语言中,字符串实际上是使用空字符\0结尾的一维字符数组\0是用于标记字符串的结束。

字符串的初始化

  1. 使用数组形式,应用大括号进行初始化。
char 字符串名[字符的个数+1]={'英文字符1','英文字符2',...,'英文字符n','\0'};

例: char logo[9] = {‘h’,‘h’,‘x’,‘x’,‘t’,‘t’,‘x’,‘s’,‘\0’};

  1. 直接使用双引号来初始化。
char 字符串名[字符的个数+1]="字符串的内容";

例: char logo[] = “hhxxttxs”;

】:1,2两种初始化方式中,中括号内的内容都可省略。

字符串的输出

  1. 使用索引遍历输出
#include 
int main(){
    char list[] = {'h','h','x','x','t','t','x','s','\0'};
    for(int i = 0; i < 9;i++){
		printf("%c ", list[i]);
	}
    return 0;
}
  1. 直接整串输出
#include 
int main(){
    char list[] = {'h','h','x','x','t','t','x','s','\0'};
    printf("%s",list);
    return 0;
}

字符串操作函数【注:待补充】

  1. putchar()

函数声明:int putchar(int c);
把一个无符号字符写入到标准输出中,如发生错误则返回EOF(-1)(end of fail)表示写失败。

与printf()函数的区别:参考文献
1)printf()为发送格式化的输出到标准输出int printf(const char *format, ...),可输出各种类型的数据;而putchar()是把一个无符号字符写入到标准输出中,只能输出单个字符。
2)printf()的返回值是正常输出的参数的数量,而putchar()的返回值则是是否正常输出。
3)printf()的时间复杂度是 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n)), 而putchar()的复杂度为 O ( 1 ) O(1) O(1),输出句子也只有 O ( n ) O(n) O(n)
4)printf()每执行一次解析一次格式串,而putchar()是编译时尽量优化。

  1. getchar()

函数声明:int getchar(void)
从标准输入读入一个无符号字符,该函数以无符号char强制转换为int的形式返回读取的字符,如果到达文件末尾或发生读入错误,则返回EOF(-1)。

与scanf()的区别:参考文献
1)scanf()为格式化输入函数int scanf(const char *format, ...),可输入各种类型的数据。而getchar()是键盘输入函数,其功能是从键盘上输入一个字符。
2)scanf()函数在读取数字时会跳过空格、制表符合换行符;getchar()只能输入字符型,输入时遇到回车键才从缓冲区依次提取字符。
3)scanf()以空格、Enter、Tab结束一次输入,不接受空格符,不会舍弃最后的回车符(即回车符会残留在缓冲区中);getchar()以Enter结束输入,接受空格符,会舍弃最后的回车符。

代码演示

#include
int main(int argc, char const *argv[]){
	int ch;
	while((ch = getchar())!=EOF){
		putchar(ch);
	}
	return 0;
}

需包含头文件string.h的字符串库函数

1)strlen()函数。计算字符串的长度。与sizeof()不同的是该函数返回的字符串长度不包含结束字符。
函数声明: strlen(const char *s);
代码演示

/*自写strlen函数:mylen*/
#include 
#include 
int mylen(const char* s){
//数组写法------------------------------------------
	/*
	int index = 0;
	while(s[index] != '\0'){
		index ++;
	}
	return index; 
-------------------------------------------------------------------*/

//指针写法---------------------------------------------------------------
	char* t = s;
	while(*t!= '\0'){
		t++;
	}
	return (t - s);	
}
//------------------------------------------------------------------------------------------ 

int main(int argc, char const *argv[]){
	char str[] = "This is a series of codes";
	printf("The number of codes of str is %d\n", mylen(str));
	return 0;	
}

2)strcmp()函数。按照ASCII码逐一比较两个字符串的大小关系。
函数声明: int strcmp(char *a, char *b)
该函数会对字符串a和b的每个字符,按照ASCII 码值逐一比较,如果二者完全相同返回0;如果字符串a的ASCII码值首先出现较大者,会返回1,否则返回-1。
代码演示

//strcmp()函数
/*函数说明
int strcmp(const char *s1, const char *s2);
0: s1==s2
1: s1>s2
-1: s1
#include 
/*自写strlen函数:mycmp*/
int mycmp(char *str1, char *str2){
//---------------------------------------------------------------------------
/*数组写法*/

       int index = 0;
       while( str1[index]==str2[index] && str1[index] != '\0'){
                      index++;
       }
       int res = -1;
       if(str1[index]==str2[index]){
	   	res = 0;
	   }else{
	   	res = (str1[index] - str2[index])/(abs(str1[index] - str2[index]));
	   }
       return res;
}
/*指针写法*/
/*
    while(*str1==*str2 && *str1 != '\0'){
       str1++;
       str2++;
      }
      int res = -1;
      if(*str1==*str2){
	  	res = 0;
	  }else{
	  	res = (*str1 - *str2)/(abs(*str1 - *str2));
	  }
    return res;
}*/
int main(void){
    char str_1[] = "abc";
    char str_2[] = "ABC";
    printf("%d\n", mycmp(str_1,str_2));
    if(strcmp(str_1,str_2)==0){
        printf("str_1 is equal to str_2\n");
    }
    return 0;
}

3)strcpy()函数。strcpy(字符串1,字符串2)复制字符串2到字符串1中。返回的是一个字符指针, 字符串2会将字符串1覆盖。

函数声明: char* strcpy(char *restrict dst, const char *restrict src).
这里 restrict 表明dst与src两个指针所指向的内存空间不重叠。

需要注意的是字符串在复制的过程中遇到\0也会进行复制,因此若源字符串(字符串2)的字符串长度小于目的字符串(字符串1)的长度的话,使用strcpy函数后新的字符串长度同源字符串一致。
代码演示

#include 
#include 
int mycpy(char *str1, const char *str2){//用于复制一个字符串
//----------------------------------------------------------------------------------
/*数组写法*/
  int index = 0;
  while( str2[index]!= '\0'){
          str1[index]=str2[index];
                 index++;
  }
  str1[index] = '\0';
  return str1;
}
//-----------------------------------------------------------------------------------------
/*指针写法*/
/*
char* res = str1;
while(*str2 != '\0'){
      *str1 = *str2;
      str1++;
      str2++;
      //*str1++=*str2++;
     }
     *str1 = '\0';
     return *res;
*/
//-------------------------------------------------------------------------------------------------
int main(int argc, char const *argv[]){
   char str1[] = "abcdefg";
   char str2[] = "ABCD";
   char str3[] = "abcdefg";
   mycpy(str1, str2);
   printf("str2 拷贝到 str1 的结果为 %s\n", str1);//(1)长度短的字符串拷贝到长度长的字符串
   mycpy(str2, str3);
   printf("str3 拷贝到 str2 的结果为 %s\n", str2);//(2)长度长的字符串拷贝到长度短的字符串
   return 0;	
}

/*
输出结果为:
str2 拷贝到 str1 的结果为 ABCD//(1)
str3 拷贝到 str2 的结果为 abcdefg//(2)
*/

4)strncpy()函数。strncpy(字符串1,字符串2,个数n)复制字符串2中的n个字符到字符串1中。返回的是一个字符指针, 字符串2会将字符串1覆盖。
函数声明: char *strncpy(char *dest, const char *src, size_t n)
代码演示

 //strncpy()函数
#include 
#include 
int myncpy(char *str1, const char *str2, int n){//用于复制一个字符串
//----------------------------------------------------------------------------------
/*数组写法*/
/*
   int index = 0;
   //while( str2[index]!= '\0'){
   while( index < n){
        str1[index]=str2[index];
        index++;
   }
   str1[index] = '\0';
   return str1;
}*/
//-----------------------------------------------------------------------------------------
/*指针写法*/

char* res = str1;
while(str1 - res < n){
       *str1 = *str2;
       str1++;
       str2++;
       //*str1++=*str2++;
      }
      *str1 = '\0';
      return *res;
}
//-------------------------------------------------------------------------------------------------
int main(int argc, char const *argv[]){
	char str1[] = "abcdefg";
	char str2[] = "ABCD";
	char str3[] = "abcdefg";
	myncpy(str1, str2, 2);
	printf("str2 拷贝到 str1 的结果为 %s\n", str1);
	myncpy(str2, str3, 3);
	printf("str3 拷贝到 str2 的结果为 %s\n", str2);
	return 0;	
}

5)strcat()函数。strat(字符串1,字符串2)将字符串2中的字符连接到字符串1中。返回的是一个字符指针。
函数声明: char *strcat(char *dest, const char *src)
代码演示

//strcat()函数
#include 
#include 
int mycat(char *str1, const char *str2){//用于复制一个字符串


//----------------------------------------------------------------------------------
/*数组写法*/

   int lenstr1 = strlen(str1);
   int index = 0, lenstr2 = strlen(str2);
   //while( str2[index]!= '\0'){
   while( index < lenstr2){
        str1[lenstr1+index]=str2[index];
        index++;
   }
   //str1[lenstr1+index] = '\0';
   str1[lenstr1+index]=str2[index];
   return str1;
}
//-----------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
/*指针写法*/
/*
int lenstr1 = strlen(str1); 
while(*str2!='\0'){
       *(str1 + lenstr1) = *str2;
       lenstr1++;
       str2++;
       //*str1++=*str2++;
      }
      *(str1 + lenstr1) = *str2;
      return *str1;
}*/
//-------------------------------------------------------------------------------------------------

int main(){
	char str1[] = "abcdefg";
	char str2[] = "ABCD";
	mycat(str1, str2);
	printf("str2 拼接到 str1 后的结果为: |%s|\n", str1);
	return 0;	
}

6)strchr()函数。strchr(字符串1,字符串2)将字符串2中的字符连接到字符串1中。返回的是一个字符指针。
**函数声明: ** char *strchr(const char *str, int c)
代码演示

//mychr()
#include 
#include 

char *mychr(const char *str, int c){
	while(*str){
		if(*str==c){
			return (void *)str;
			break;
		}
		str++;
	}
	return NULL;	
}

int main(){
	char *str = "haohaoxuexi,tiantianxiangshang";
	char c = 'u';
	char *ret = NULL;//没有位置指定时好习惯是先指向空位置
	char *res = NULL;
	
	ret = strchr(str, c);
	printf("使用库函数strchr的返回结果为%s\n", ret);
	
	res = mychr(str,c);
	printf("使用自定义函数mychr的返回结果为%s\n", res);
	return 0;		
}

7)strrchr()函数。strrchr(字符串,字符)在参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置。
**函数声明: ** char *strrchr(const char *str, int c)
代码演示

//mychrr()
#include 
#include 

char *mychrr(const char *str, int c){
	int index= 0; 
	char *str2 = (char *)str;//保持数据类型的一致性
	while(*str){
		if(*str==c){
			index = (str-str2);
		}
		str++;
	}
	if(index==0){
		return NULL;
	}else{
		return (void *)(str2+index);
	}	
}

int main(){
	char *str = "haohaoxuexi,tiantianxiangshang";
	char c = 'n';
	char *ret = NULL;//没有位置指定时好习惯是先指向空位置
	char *res = NULL;
	
	ret = strrchr(str, c);
	printf("使用库函数strrchr的返回结果为%s\n", ret);
	
	res = mychrr(str,c);
	printf("使用自定义函数mychrr的返回结果为%s\n", res);
	return 0;		
}

8)strstr()函数。strstr(字符串1,字符串2)在字符串1中查找第一次出现字符串2的位置,不包含终止符 ‘\0’。
**函数声明: ** char *strstr(const char *first, const char *second)
代码演示】复制链接

//复制自https://blog.51cto.com/thinkerfans/1351064
#include 
#include 

char *mystrstr(const char*, const char*);
char *mystrstr(const char *src, const char *find){
	if(NULL==src||NULL==find){
		return NULL;
	}
	
	char *cp = (char *)src;
	char *s1, *s2;
	
	while(*cp){
		s1 = cp;
		s2 = (char *)find;
		while(*s1 && *s2 &&(*s1 == *s2)){
			s1++, s2++;
		}
		if(!*s2){
			return cp;
		}
		cp++;
	}
	return NULL;	
}

int main(){
	char *src = "hello, china and hello, world";
	char *find = ",";
	char *re = mystrstr(src, find);
	char *res = strstr(src, find);
	if(re){
		printf("%s\n", re);
	}else{
		printf("no find\n");
	}
	printf("%s\n", res);
	return 0;
}

9)strcasestr()函数。strcasestr(字符串1,字符串2)同strstr()函数功能一样,区别是strcasestr将大小写都用小写字符来匹配。在字符串1中查找第一次出现字符串2的位置,不包含终止符 ‘\0’。
**函数声明: ** char *strcasestr(const char *first, const char *second)
代码演示】复制链接

//复制自https://blog.51cto.com/thinkerfans/1351698
#include
#include //tolower()函数头文件 
#include
char * mystrcasestr(const char * ,const char *);
char * mystrcasestr(const char *src, const char *find){
    if(NULL == src || NULL == find)
        return NULL;
    char *cp =  (char *)src;
    char *s1 , *s2;
    while(*cp){
        s1 = cp;
        s2 = (char * )find;
        while(*s2 && *s1 && !(tolower(*s1) - tolower(*s2)))
            s1++,s2++;
        if(!(*s2))
            return cp;
        cp++;
    }  
    return NULL;
}
int main(){
    char *src = "HeLlO, china and hello,world";
    char *find = "hElLo,";
    char *re = mystrcasestr(src,find);
    if(re)
        printf("%s\n",re);
    else
        printf("no find\n"); 
    return 0;
}

10) tolower()函数。tolower(int 字符)将大写字符转化为小写字符。头文件为#include
**函数声明: ** int tolower(int c);

//mytolower
//参考自 https://blog.51cto.com/thinkerfans/1351723
#include
#include
#include 
int mytolower(int c){
    if('A'<=c && 'Z'>=c)
        return c-'A'+'a';
    return c;
}
char mytolower2(char c){
    if('A'<=c && 'Z'>=c)
        return 'z'-('Z'-c);
    return c;
}
int main(){
    char s1[] = "3489 ASDFDF adfdf +-*/";
    char s2[] = "3489 ASDFDF adfdf +-*/";
    unsigned int i=0;
    //int i=0;
    
	
    for(;i < strlen(s1);i++){
        s1[i] = mytolower2(s1[i]);
        s2[i] = tolower(s2[i]);
    }
    printf("s1=%s\n",s1);
    printf("s2=%s\n",s2);
    return 0;
}

11) toupper。toupper 字符)将小写字符转化为大写字符。头文件为#include
**函数声明: ** int upper(int c);

//mytoupper
//参考自 https://blog.51cto.com/thinkerfans/1351723
#include
#include
#include 
int mytoupper(int c){
    if('a'<=c && 'z'>=c)
        return c-'a'+'A';
    return c;
}
char mytoupper2(char c){
    if('a'<=c && 'z'>=c)
        return 'Z'-('z'-c);
    return c;
}
int main(){
    char s1[] = "3489 ASDFDF adfdf +-*/";
    char s2[] = "3489 ASDFDF adfdf +-*/";
    unsigned int i=0;
    //int i=0;
    
	
    for(;i < strlen(s1);i++){
        s1[i] = mytoupper2(s1[i]);
        s2[i] = toupper(s2[i]);
    }
    printf("s1=%s\n",s1);
    printf("s2=%s\n",s2);
    return 0;
}

字符串数组

由多个字符串构成的数组。

  • char **a 表示a是一个指针,指向另一个指针,被指向的指针指向一个字符串。
  • char a[][] 第二维需要有确切的大小
  • char *a[]
    C语言学习笔记4---数组、字符串_第1张图片
    代码示例
#include
int main(){
	printf("请输入月份:");
	int month;
	scanf("%d",&month);
	char *a[]={"January","February","March","April","May","Jane","July","August","September","Octobor","November","December"};
	printf("%s\n", a[month-1]); 
	return 0;
}

重要链接

1. http://www.jbox.dk/sanos/source/lib/string.c.html
2. http://www.rowleydownload.co.uk/maxq30/documentation/index.htm?http://www.rowleydownload.co.uk/maxq30/documentation/strcasestr.htm
3. http://www.jbox.dk/sanos/source/lib/ctype.c.html
https://blog.51cto.com/thinkerfans

参考文献

C|菜鸟教程。链接
thinkerfans 博客。链接

你可能感兴趣的:(C语言学习笔记,c语言)