您的位置:首页 > 编程语言 > C语言/C++

C语言第五节-原码-数组-字符串

2015-09-28 22:03 288 查看
原码-反码-补码

数据在计算机内部以补码的形式存储的
数据分为:有符号(正数最高位是0,负数是1)数和无符号数(都是正数)
对于正数:反码==补码==原码
对于负数:反码==除最高符号位以外的各位取反 补码=反码+1
原码:最高位的符号位+真值
反码:正数→本身
负数→反码==除最高符号位以外的各位取反
为何要引入反码-补码?
补码:使计算机能够做减法 ,简化电路设计 (1 - 1等价于1 + (-1) 只有补码能实现)
正数→本身
负数→补码=反码+1
补码→原码:符号位不变,取反+1


//64位机器侠

//int
类型占用4个字节,每个字节8位

//计算机存储1
使用32位的二进制数码,存储的是补码



//+1

//原码:000000000000000000000000000000001

//反码=原码

//补码=原码



int
b1 = 0b000000000000000000000000000000001;//0b表示二进制数binary

printf("b1 = %d\n", b1);



//-1

//原码:100000000000000000000000000000001

//反码:111111111111111111111111111111111

// +000000000000000000000000000000001

// ---------------------------------

//补码:111111111111111111111111111111111

int
b2 = 0b11111111111111111111111111111111;

printf("b2 = %d\n", b2);

位运算符

位运算符:指按二进制进行的运算(用于整数二进制位之间的运算)
符号:& 按位与:如果两个位进行&操作,同1为1,有0为0,每一位进行比较
9&5
00001001
& 00000101
-------------------
00000001
实用:1、任何数&1,只看数的最低位
2、改变某一位,例如改变第30位为0
//...00000100
//...11111011

| 按位或:同0为0,有1为1,每一位进行比较


~ 按位取反:0→1,1→0


^ 按位异或:相同为0,不同为1,每一位进行比较


>> 右移位:高位要补原来的符号位,移除部分要舍弃,不会改变正负
//相当于原数/2^n

<< 左移位:各二进制位左移N位,高位丢弃,低位补0,左移可能会改变一个数的正负
// <<
左移位


// 8 << 2
各二进制位左移N位,高位丢弃,低位补0

// 00000000000000000000000000001000 8


// →00000000000000000000000000100000 32

// 相当于原数*2^n
8*2^2

数组(构造类型)

数组:为了处理方便,把具有相同类型的若干变量按有序的形式组织起来,这些按序排列的同类数据的集合
数组元素:构成数组的数据
数组的下标:数组元素的位置的一个索引或指示
按存储的内容分类:数值数组、字符数组、指针数组、结构数组
按维度分类:一维数组、二维数组、多维数组(维度跟下标的个数有关)

数组元素作为函数的参数,进行数据的传递:1、数组元素作为实参实用(单向值传递)
2、数组名作为函数的形参和实参实用

一维数组:所有元素都不是数组(元素为基本数据类型)
定义方式:
类型说明符 数组名[常量表达式];
常量表达式:表示元素的个数,也是数组的长度
数组的长度:可以使用宏定义
初始化:
1、定义的同时初始化
int a[3] = {1,2,3}; //全部初始化
int b[3] = {1,2}; //部分初始化 ,未写的为0
int c[ ] = {1,2,3}; //已知元素,可不写数组长度
int d[10] = {[3]=23, [8]=34}; //下标为3,8的赋初值,其余为0
2、先定义后初始化,类似变量

数组定义后,不初始化,数组里面有值,值为系统随机的垃圾值,所以正确的使用数组需要初始化

数组的遍历:通过for循环,可以依次访问数组的每一个元素
1、正序输出

a
= { …..};
for(int i = 1;i < n;i++) {
printf(“%d “, a[i]);
}

2、倒序输出

for(int i = n-1; i >= 0; i--){
printf(“%d “, a[i]);
}

//从键盘输入一个数组长度,构建一个数组,然后再通过for循环从键盘接受数组的数组初始化,并且for循环输出查看

//1、从键盘输入长度

int
length = 0;

printf("请输入一个长度:");

scanf("%d", &length);

//2、构建数组

int
a[length];

//3、数组初始化

for
(int
i = 0; i < length; i++) {

printf("请输入数组的第%d个值:",
i + 1);

scanf("%d", &a[i]);

}

//4、数组输出

for
(int
i = 0; i < length; i++) {

printf("%d ", a[i]);
}

数组的存储
%p:输出地址
存储方式:1、计算机会给数组分配一块连续的存储空间
2、数组名代表数组的首地址,从首地址开始,依次存入数组元素
3、每个元素的字节数相同(取决于数组类型)
4、元素之间地址连续
先定义的变量或数组存在高地址,数组先分配好长度的内存单元,然后依次存储(从低位到高位),数组元素内部连续

一维数组的地址:数组名代表数组的首地址
a == &a[0]
一维数组的长度:
数据类型 a
;
数组占用的总字节数:存储n个 * 每个都是sizeof(数据类型)
数组长度:数组的总长度 / 数组的任何一个元素在内存中占用的字节数(元素类型)

length = sizeof(a)/ sizeof(int)

数组越界:编译警告,即使没有报错(版本不一样,可能报错),也是不安全的,越界地址的值有可能丢失

//通过for循环,依次输入10个数,保存在数组中,找出最大值



int
a[10];

//输入10个数

for
(int
i =0; i <
10; i++) {



printf("当前输入第%d个数:",
i + 1);

scanf("%d", &a[i]);

}

//找出最大值

int
max = a[0];//假设a[0]为最大值max

for
(int
i = 1; i <
10; i++) {

if
(max < a[i]) {

max = a[i];

}

}

printf("max = %d\n", max);

数组作为参数
1、数组元素作为实参时,函数的形参不必须是数组(类型 x) --int x 值传递不改变值
2、数组名作为实参时,函数的形参必须是数组(类型 arr[])—int
arr[] 地址传递可改变值
3、数组名作为形参时,长度可以不写
4、数组名作为参数时,数组长度信息会丢失(C中,不管什么类型,数据的内存地址在内存中都是8个字节------数组名就是地址)

数组名作为参数时的注意点:
形参数组类型和长度要与实参一致,否则会造成错误

冒泡排序

冒泡排序(Bubble Sort):一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来,走访数列的工作时重复地进行,直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来时因为越小的元素会经交换慢慢“浮”到数列的顶端。

冒泡排序分为:
大数下沉 小数上浮

冒泡排序步骤(大数下沉法)

冒泡排序:使用两层循环,外层控制次数,内层逐个比较,n个数比较n-1次,

冒泡排序代码实现
//冒泡排序


int
a[6] = {2,
5,
3,
1,
7,
4};



for
(int
i = 0; i <
sizeof(a) /
sizeof(int) -
1; i++) {
//-i:因为每一次内外循环结束,都有一个数已经排序好了,-i防止重复比较,优化效率


for
(int
j = 0; j <
sizeof(a) /
sizeof(int) -
1
- i; j++) {

if
(a[j] > a[j+1]) {

// int temp = a[j];

// a[j] = a[j+1];

// a[j+1] = temp;

arraySort(a, j);
}
}

}



for
(int
i = 0; i <
sizeof(a) /
sizeof(int); i++) {

printf("%d\t",
a[i]);
}
//数组的交换值
void
arraySort(int
arr[] ,
int n) {



int
temp = arr
;

arr
= arr[n+1];

arr[n+1] = temp;


}

选择排序

选择排序(Selection sort):是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
选择排序是不稳定的排序方法。

选择排序流程:

选择排序代码实现:
//选择排序:每一趟都找到一个最小或最大数,放在首位

int
a[6] = {3,
4,
2,
10,
5,
8};



// for (int i = 0; i < sizeof(a) / sizeof(int); i++) {

// for (int j = i + 1; j <= sizeof(a) / sizeof(int) - 1; j++) {

// if (a[i] > a[j]) {

// int temp = a[i];

// a[i] = a[j];

// a[j] = temp;

// }

// }

// }

selectSort(a,
6);





for
(int
i = 0; i <
6; i++) {

printf("%d\t", a[i]);
}

//选择排序函数封装
//传入数组长度len,因为数组在作为地址传入时,长度会丢失
void
selectSort(int
arr[],
int len) {

for
(int
i = 0; i < len -
1; i++) {

for
(int
j = i + 1; j < len; j++) {

if
(arr[i] > arr[j]) {

int
temp = arr[i];

arr[i] = arr[j];

arr[j] = temp;

}

}

}

}

折半查找

折半查找:在一个有序的表中,取中间元素作为查找对象,若给定值与中间元素的要查找得数相等,则成功;若小于,则在中间元素的左半区查找;反之,右半区。不断重复上述步骤,直至结束。

折半查找步骤:
0 1 2 3 4 5
12 45 22 56 40 19
low high

key = 45
mid = (low + high)/2
循环
key(45) < a[mid]
high = mid - 1;

key(45) > a[mid]
low = mid +1;

key(45) == a[mid]
return mid;

当low > high ,查找不到

折半查找代码实现:
//折半查找代码实现



//数组元素必须有序,才可以折半查找

int
a[] = {2,
3,
4,
6,
10,
25,
30,
40,
44};



//查找key = 40

int
location = searchLocation(a,
9,
40);

printf("location = %d\n", location);

//折半查找函数实现

//arr数组 len数组长度
key要查找的数
//return
要查找的数的位置,
如果查找不到返回 -1
int
searchLocation(int
arr[],
int len,
int key) {

//先要定义变量

int
low = 0, high = len-1, mid;



//循环

while
(low <= high) {

//计算mid的位置

mid = (low + high) / 2;



/*

判断
key与a[mid]的关系



key > a[mid] low = mid +1

key < a[mid] high = mid - 1

key == a[mid] return mid

*/

if
(key > arr[mid]) {

low = mid + 1;

} else
if (key < arr[mid]) {

high = mid - 1;

} else
{

return
mid;

}

}

//查找不到
return -1

return
-1;
}

二维数组

二维数组:是特殊的一维数组(一维数组的每个元素又被声明为一维数组)
定义:类型说明符 数组名[常量表达式1][常量表达式2]
a[i][j]:i行 j列
a[3][4]:
3行 4列
一维数组 一维数组的元素又是一位数组
a[0]——---a[0][0] a[0][1] a[0][2] a[0][3]
a→a[1]——---a[1][0] a[1][1] a[1][2] a[1][3]
a[2]——---a[2][0] a[2][1] a[2][2] a[2][3]


初始化:类似一维数组
完全初始化:
分段初始化:int [2][3] = {{2, 3, 4}, {7, 5, 6}};
连续赋值:int [2][3] = {2, 3, 4, 7, 5, 6}; 计算机根据第二维自动判断
省略第一维:int [][3] = {2,
3, 4, 7, 5, 6}
部分初始化:

int [2][3] = {1};
1 0 0
0 0 0

int [2][3] = {{1}, {2}};
1 0 0
2 0 0

二维数组的遍历
二维数组的元素称为双下标变量,表示形式: 数组名[第一维下标][第二维下标]
//遍历二维数组

int
a[2][3] = {1,
2,
3,
6,
5,
4};



for
(int
i = 0; i <
2; i++) {

for
(int
j = 0; j <
3; j++) {

printf("%d\t", a[i][j]);

}

printf("\n");
}

a[2][2]分析:

int
a[2][2] = {1,
2,
3,
4};

//数组的首地址

//二维数组:数组的首地址
==
数组名 == &a[0] ==&a[0][0]

printf("a = %p\n", a);

printf("&a[0] = %p\n", &a[0]);

printf("&a[0][0] = %p\n", &a[0][0]);

二维数组的行数和列数:
//二维数组占用的总字节数:1、总字节数
=
每行占用的字节数之和

// 2、总字节数
=
元素的个数 *
元素的类型

// =

* 列
* sizeof(数组类型)

// =sizeof(数组名)

int
len = 2
* 2
* sizeof(int);
//16

printf("%d\n", len);

len = sizeof(a);
//16

printf("%d\n", len);


//每行的字节数如何计算

//int[2][2]

//a[0]→1 2

//a[1]→3 4

len = sizeof(a[1]);
// 8

printf("%d\n", len);



//每一行有多少列

//列数
=
行的总字节数 /
每个元素占用的字节(数据类型)

len = sizeof(a[1]) /
sizeof(int);
//2

printf("%d\n", len);

//行数:总字节数
/
每一行占用的字节数

len = sizeof(a) /
sizeof(a[0]);
//2

printf("%d\n", len);

//有一个5 X 3的矩阵,要求编程以求出其中最大的那个元素及其所在的行号和列号

//算法:将a[0][0]作为临时最大值Max,然后逐一比较,当a[i][j]
> max, max = a[i][j]



int
a[5][3] = {

{1,3,4},

{55,2,5},

{6,9,10},

{11,15,66},

{34,22,34}

};

int
max = a[0][0];

int
maxRow = -1, maxCol = -1;

//i:行row j:列col

for
(int
i = 0; i <
5; i++) {

for
(int
j = 0; j <
3; j++) {

if
(a[i][j] > max) {

max = a[i][j];

maxRow = i;

maxCol = j;

}

}
}
//由于数组的下标从0开始,所以统计行列应该加1

printf("最大值:%d\n在第%d行第%d列!",
max, maxRow + 1, maxCol +
1);

二维数组作为函数参数:
1、数组元素作为函数参数(值传递)
2、数组名作为函数的参数,可以修改值(地址传递)
3、数组名作为某一函数的参数时,同样,该函数里不能计算该数组的字节,长度丢失
4、数组名作为形参时,可以不写第一维的长度

//从键盘接受两个参数分别存到m,n中,使用m和n构成数组

//1、定义一个函数,使用
i, j初始化数组a[i][i]

//定义一个函数打印二维数组的每个值

//scanf() m,n

//int array[m]

//init_arr(arr,m,n)

//print_arr(arr,m,n)

int
m = 0, n=
0;



printf("请输入两个数,确定数组的行数和列数:");

scanf("%d %d", &m, &n);

int
array[m]
;



//传参数,应该先传行列m,n,不然定义的函数中形参arr[][]不知道时几行几列

init_arr(m, n, array);

print_arr(m, n, array);

//初始化数组

void
init_arr(int
m,int
n ,int
arr[m]
) {

for
(int
i = 0; i < m; i++) {

for
(int
j = 0; j < n; j++) {

//给每个元素赋值,使用i*j

arr[i][j] = i * j;

}

}

}

//打印数组的值

void
print_arr(int
m, int
n, int
arr[m]
) {

for
(int
i = 0; i < m; i++) {

for
(int
j = 0; j < n; j++) {

printf("%d\t", arr[i][j]);

}

printf("\n");

}
}

字符串:“”

字符串:位于双引号“”中的字符序列
在内存中以’\0’结束,所占字节比实际多一个
字符串“HELLO”在内存中的存储方式:
H E L L O \0
C语言中,没有字符串类型的变量,可以用字符数组存储字符串

字符数组
一维数组:char 数组名[常量表达式]
二维数组:char 数组名[常量表达式1][常量表达式2]

%s:输入输出一个字符串,直至\0结束


//字符串的输入输出

char
str[10] =
"hello";

//%c打印字符

for
(int i =
0; i <
10; i++) {

printf("%c\t", str[i]);

}



//%s输出一个字符串

//从给定的地址开始,直至\0结束

printf("%s\n", str);

//%s输入一个字符串

char
str[10];

scanf("%s",
str);

printf("---->%s",str);
注意:1、如果以%s格式进行输入,注意空格问题。如果输入的字符串有空格,则空格之后的字符无法被接 受保存(scanf遇到空格就结束了)
2、输入的字符长度要小于数组的长度

字符串结束符\0:
1、char a[] = “abc”; //系统自动加上\0,所以数组长度必须够存上\0
2、char b[] = {‘a’, ‘b’, ‘c’, ‘\0’};//这种写法最好带上\0

字符串长度的计算方法:计算字符串长度时,不包含\0
(字符串占用空间数包含\0)
1、使用字符串函数strlen(数组名)
2、以\0作为条件判断,遇到\0结束,\0之前的就是字符串长度
char a[] = “abc”;
int i = 0;
while(a[i] == ‘\0’)i++;

//判断字符串中是否包含某个字符,如果包含,返回其首次出现的位置,否则返回-1

char
str1[] = "abcdefghijk";

int
index = searchIndex(str1,
'e');

printf("%d\n", index);

//查找字符的位置

//传入数组名,待查找字符

int
searchIndex(char
str[], char
key) {

//通过循环依次取得每个字符串的字符

//循环条件
str[i] != '\0'

//如果没有结束,开始比较
key str[i]

for
(int
i = 0; str[i] !=
'\0'; i++) {

if
(str[i] == key) {

return
i;

}

}



return
-1;
}

%s不可以接受空格
字符串处理函数

字符串的函数头文件“string.h”
1、puts():输出一个字符串 stdio.h
puts(数组名):可以自动换行,可以传地址,必须是字符数组,不可以格式化输出
2、gets():输入一个字符串 stdio.h

gets(数组名):可以接受空格,存在越界(不安全)

3、strcat():连接一个字符串 “string.h”

strcat(A,B):A要足够大
4、strcpy():字符串拷贝函数 “string.h”
strcpy(old,new):new替换old,old要足够大
5、strcmp():字符串比较函数 “string.h”
strcmp(str1,str2):逐个对应位相比较(ASCII码或字典出现顺序),返回值>0,<0,==0
6、strlen():字符串的长度计算函数 “string.h”
strlen():不包含\0

//实现单词首字母大写,并统计单词个数

//定义变量

char
str[100];

int
word = 0;

int
count = 0;//统计单词的个数

//提示用户输入字符串

printf("请输入一个字符串:\n");

//接受字符串

gets(str);

//循环取出每一个字符,遇到\0循环结束

for
(int
i = 0; str[i] !=
'\0'; i++) {



//判断

if
(str[i] == ' ') {

//把是否是单词的标记改一下

word = 0;//这是一个标记,word
= 0表示一个单词

} else
if (word ==
0) {

//当前循环
字符时空格
下次循环一定是一个单词

count++;

str[i] = str[i] -
32;//减去32就是大写

word = 1;
//表示不是一个单词

}

}



printf("单词个数:%d,字符串:%s\n",
count, str);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: