day7 c:字符串和 字符串数组(字符指针数组很重要)!!!

字符串字面值

如“Hello world”等字符串常量(字面值一定是常量,但常量不一定是字面值)

三种书写方式:

int main(void){

        printf("i love xixi  --fp\n");

        printf("i love xixi\                     // \是省略换行符,但下一行的空白也算在里面

  --fp\n");

        printf("i love xixi"

                "  --fp\n");

        return 0;

}

内存模型 

字符串字面值所支持的操作 

 常量数组支持的操作字符串字面值都支持

 “ABC”[0]='a' ;            //“ABC”是数组名,这个操作是错误的,因为字符串字面值在代码段

char* p="ABC"+1;     //c中不是拼接,而是数组名“ABC”即地址,然后+1

printf("%c\n",*p);      //B

字符串变量

1.c没有字符串类型,依赖于字符数组

2.字符串必须以'\0'结尾

3.在c中求字符串长度不是O(1)的时间复杂度而是O(n)--->

                                                                        char str[]="hello world\n";int len=strlen(str);

注:strlen不包含空字符'\0'的长度

声明字符串变量并赋初始值

char str1[]={'H','e','\0'};

char str2[]="He"

char str[5]="hello"不是字符串而是字符数组,字符串都是以'\0'结尾

char str[10]="Hello"  :字符数组str长度10,字符串Hello长度5 ,占用6个空间

字符串读和写

1.printf+%s

注意:字符串读取可以直接在printf中写首地址---->返回的是首地址指向的内容※※

   scanf+%s(读取一个单词)

char arr[MAX]="    hello world";
scanf("%s",arr);
printf("%s",arr);  //hello

%s匹配规则:

        忽略前置空白字符,

        读取字符填入字符数组,

        遇到空白字符结束(不会将换行,空格等读入内存)

缺点:1.不能读取空白字符   2.不会检查字符越界

注:用scanf读取字符串到字符数组时会自动添加'\0'。%c不会自动添加终止符,而%s会 

2.puts/gets(读取一整行)

注:scanf和puts效果都是把'\n'---->'\0',然后存入内存

3.fgets(str,MAX_LINE,stdin)

和gets区别:1.会检查是否越界   2.会存储'\n'并在后面添加'\0';

字符串操作  

strlen 

当两个相同类型的指针相减时,编译器知道每个元素占用的字节数,从而可以正确地计算出两个指针之间相隔的元素个数,而不是简单的字节差。 

strlen()不会计算字符串中的编译器自动添加的空字符'\0' ,但会计算" "

  • 空格:普通字符,ASCII 32,存储为可见字符。
  • '\0':终止符,ASCII 0,自动添加,不可见。

strcpy 和 strncpy(防数组越界)

 

这两个都会将空字符'\0'作为结束并复制'\0' ----->

但strncpy中   要复制的前n个元素最大个数为【数组 -1】且要手动 s1[数组-1]=‘\0’※※

字符串拼接strcat 和 strncat(同上)

strcmp(s1,s2)

规则:字符串长的>0   --->   ASCLL大的>0

size_t my_strcmp(const char* s1,const char* s2){

        while(*s1 && *s2){

                if(*s1 != *s2){

                        return *s1-*s2;

                }

                s1++;   //s1+1个char地址

                s2++;

        }

        return *s1-*s2;

}

作业

1.

void reverse_print() {
	char c;
	char messages[100];
	int i = 0;
	c = getchar();
	while (c != '\n' && i != 99) {
		messages[i] = c;
		c = getchar();
		i++;	
	}
	for (int j = i - 1; j >= 0; j--) {
		printf("%c", messages[j]);
	}
}
void reverse_print() {
	char c;
	char messages[100];
	char* p = messages;
	c = getchar();
	while (c != '\n' && p<p+100) {
		*p = c;
		c = getchar();
		p++;	
	}
	p--;
	for (; p >= messages;p--) {
		printf("%c", *p);
	}
}

2.

考虑大小写并且不忽略任何char 

bool is_pri(char messages[], int n) {
	for (int i = 0; i < n / 2; i++) {
		if (messages[i] != messages[n - 1 - i]) {
			return false;
		}
	}
	return true;
}
bool is_pri(char messages[], int n) {
	char* start = messages;
	char* end = messages + n;
	while (start<end) {
		if (*start != *end) {
			return false;
		}
	}
	return true;
}

3.

void remove_filename(char* url) {
	char* p = url;
	while (*url) {
		if(*url =='/') {
			p = url;
		}
	}
	if (*p == '/') {
		*p = '\0';
	}
}

4.

void min_max() {
	char smalllest_word[4], largest_word[4];
	char curr[4];
	scanf("%s", curr);
	strcpy(smalllest_word, curr);
	strcpy(largest_word, curr);
	while (strlen(curr) != 4) {
		scanf("%s", curr);
		if (strcmp(curr, largest_word) > 0) {
			strcpy(largest_word, curr);
		}
		if (strcmp(curr, smalllest_word) < 0) {
			strcpy(smalllest_word, curr);
		}
	}
	printf("min=%s,max=%s", smalllest_word, largest_word);
}

5.

统计字符串str中各个字符出现的频度,a[]存放各个不同字符,b[]存放对应的字符出现的频度,返回不同字符个数 

int fun(char str[], char a[], int b[]) {
	int len = strlen(str),cur=0;//cur为遍历str的不同字符·
	for (int i = 0; i < len; i++) {
		b[i] = 0;
	}
	a[0] = str[0];
	b[0] = 1;
	cur++;
	for (int i = 1; i < len; i++) {
		for (int j = 0; j < i; j++) {
			if (str[i] == str[j]) {
				int k;
				for (k = 0; a[k] != str[i]; k++);
				b[k]++;
				break;
			}
			a[cur] = str[i];
			b[cur]++;
			cur++;
		}
	}
	return cur;
}

6.

求两个字符串s和t的一个最长公共子串

//s一个个往后加,分别和t比较(t不变位置)
char com[10];//公共数组要定义在外面,定义在内部函数销毁后返回的是悬空指针
char* maxlength(char* s, char* t) {
	char*m,*n;
	int len=0,len1=0,i,j;
	while (*s) {
		//用m遍历s,n遍历t,每次s+1重置len1=0
		m = s;
		n = t;
		while (*n) {	
			len1 = 0;
			for (i=0; *(m+i) == *(n+i); i++) {
				len1++;
			}
			if (len1 > len) {
				len = len1;
				for (j = 0; j < len1; j++) {
					com[j] = *(m + j);
				}
				com[j] = '\0';
				n += i;
			}
			else {
				n++;
			}
		}
		s++;
	}
	if (len == 0) {
		return NULL;
	}
	else {
		return com;
	}
}
int main(void) {
	char  * p;
	char s[] = "aababcabcdabcde";
	char t[] = "xabcdy";
	p = maxlength(s, t);
	for (int i = 0; p[i]!='\0'; i++) {
		printf("%c", p[i]);
	}
	return 0;
}

7.

输入两个英文句子,每个句子里英文单词用空格分隔,最后输出两者的最长公共单词

char* maxword(char* s1, char* s2) {
	char from_s1[10],*temp,from_s2[10],com[10];
	int maxlen = 0, is_cur_same = 0, i, j;
	while (*s1) {
		while (*s1 == ' ')s1++;
		for (i = 0; *s1 != '\0' && *s1 != ' '; i++, s1++) {
			from_s1[i] = *s1;
		}//从左到右找到s1的某个单词存入from_s1中
		from_s1[i] = '\0';
		if (i > maxlen) {//is curr max but don,t know is same?
			is_cur_same = 0;
			temp = s2;//用temp在s2进行遍历
			while (*temp && is_cur_same == 0) {
				while (*temp == ' ')temp++;
				for (j = 0; *temp != '\0'&&*temp!=' '; j++, temp++) {//在s2中找一个个单词存入from_s2中
					from_s2[j] = *temp;
				}
				from_s2[j] = '\0';
				if (i == j) {
					if (strcmp(from_s1, from_s2) == 0) {
						maxlen = i;
						is_cur_same = 1;
						strcpy(com, from_s1);
					}
				}
			}
			
		}
	}
	if (maxlen == 0) {
		return NULL;
	}
	else {
		return com;
	}
}
int main() {
	char s1[10], s2[10];
	char* p;
	fgets(s1,sizeof(s1),stdin);
	fgets(s2, sizeof(s2), stdin);
	p = maxword(s1, s2);
	if (p == NULL) {
		printf("没有公共单词");
	}
	else {
		printf("最长公共单词=%s", p);
	}
	return 0;
}

8.

有一个2*3和3*2的整数矩阵a,b相乘,请使用指针数组实现这两个矩阵相乘,存在c中

int main(void) {
	int a[2][3] = { 1,1,1,   1,1,1};
	int b[3][2] = { 2,2  ,2,2  ,2,2 }, c[2][2] = { 0 };
	int* p[3] = { a[0],b[0],c[0] };
	int temp;
	for (int i = 0; i < 2; i++) {
		for (int j = 0; j < 3; j++) {
			for (int k = 0; k < 2; k++) {
				*(p[2]+2*i+k)+= *(p[0] + 3 * i + j) * (*(p[1] + 2 * j + k));//c[i][k]+=a[i][j]*b[j][k]
			}
		}
	}
	for (int i = 0; i < 2; i++) {
		for (int j = 0; j < 2; j++) {
			printf("%d", *(p[2] + 2 * i + j));
		}
	}
	return 0;
}

字符串数组 

字符数组的数组---->二维字符数组

1.浪费内存空间   

2.交换字符串很不方便

3.注:planets[0]和planets[1]的长度为7和5,但两个所占内存空间都为8

4.里面存的可以改变

字符指针数组

1.里面的“Mercury”等是字符串字面值,即本身内容的地址,是 char*

2.不可以直接    *(planets[i])="mercury"   进行修改.

3.要修改{.....}里的内容要创建一个字符串变量(一维字符数组),然后用指针指向那个一维数组
              char a[]="hello";planets[i]=a;

        or  char*p="hello";planets[i]=p;    //注意“hello”是字符串字面值不能p[i]='d'修改

程序题(二维字符数组)

1.输入若干字符串,找出其中最长的字符串并输出,要求采用指针数组存放这些字符串 

char* findmax(char* str[],int n,int* len) {//n是字符串个数,len是最长字符串长度
	int temp, max = 0;
	char* p;
	for (int i = 0; i < n; i++) {
		temp = strlen(str[i]);
		if (temp > max) {
			max = temp;
			p = str[i];
		}
	}
	*len = max;
	return p;
}
int main(void) {
	char* s[5],*p;
	for (int i = 0; i < 5; i++) {
		s[i] = (char*)malloc(20);
		scanf("%s", s[i]);
	}
	return 0;
}

2.求三个字符串的最长公共子串

不能以其中一个为母串,遍历寻找第二个串中的子串这种方法:这种只适合两个串找最长公共子串,其实也可以但更麻烦

要采用“求n个字符串的最长公共子串”通用的方法:如下以其中一个为子串,对比其余串找

char* copy(char* s, int start, int count) {
	static char str[20];
	for (int i = start; i < start + count; i++) {
		str[i - start] = s[i];
	}
	str[start + count] = '\0';
	return str;
}
char* common_str(char* str[],int n) {
	int len = strlen(str[0]);//这个作为子串
	int max_str = 0,index,is_true;
	char* temp;
	char result[10];
	for (int i = 0; i < len; i++) {
		for (int j = 1; j < len - i; j++) {
			temp=copy(temp, i, j);
			index = 0;
			is_true = 1;
			while(index<2){
				index++;
				if (strstr(str[index], temp) == 0) {//判断temp是否为str[index]的子串
					is_true = 0;
				}
			}
			if (is_true == 1 && strlen(temp) > max_str) {
				max_str = strlen(temp);
				strcpy(temp, temp);
			}
		}	
	}
	if (max_str == 0) {
		return NULL;
	}
	else {
		return result;
	}	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值