黑马程序员—-C语言入门十重奏之七相离

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

今天的内容让人迷糊,让人费解,让人晕乎乎,学的久了,也该换换脑子了,这几个排序也算是初级面试题吧,试试看,能不能分析明白。
最先讲的还是新的数据类型数组。
1.  数组基本概念
具有相同类型的若干变量有序的组织起来
    属于构造数据类型,一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或构造类型
2.数组的几个名词
数组元素
数组的下标
数组元素的位置的一个索引或指示
数组的维数
数组下标的个数分为一维、二维、三维、多维
3.   分类
 按元素不同:数值、字符、指针、结构、字符串
 按维度分类:一维、二维、多维

一维数组
一个数组里存储的全是基本数据类型
类型说明符 数组名[常量表达式];
int s[n];
c语言中c99标准数组长度不可以为变量
而xcode可以:
int len = 5;
int a[len]; 这种情况是不可以初始化的
数组长度可以用宏定义:
#define宏定义
#define len 5
int a[len];
    int a[3] = {1,23};
    int a1[3] = {[1] = 23,[2] = 34};
    int a2[3];
    a2[0] = 1;
    a2[1] = 2;
    a2[2] = 3;
    int len = 3;
    int a3[len];//这种情况是不可以初始化的
    a3[0] = 1;
    a3[1] = 2;
    a3[2] = 3;
注意:
1.如果定义时没有初始化,数组元素是有值的,是垃圾值
2.如果定义时进行了部分初始化,那么其他元素被系统自动初始化为0
3.字符型数组定义时如果部分初始化了,那么其他元素被系统自动初始化为0了,字符表示null

数组的存储方式:
1.  计算机会给数组分配一块连续的存储空间
2.  数组名代表数组的首地址,从首地址依次存入数组的第1、2、3、。。。个元素
3.  每个元素占用相同的字节数
4.  并且元素之间的地址是连续的

一维数组的地址:
//  定义两个数组,两个数组地址不一定连续。数组名代表了数组的首地址
//  数组内部各元素的地址是连续的int型数组内部元素之间相差4字节。
//  数组名创建了内容后,不允许再修改了

#include <stdio.h>

int main(int argc, const char * argv[]) {
    int a[] = {1,2};
    int b[5] = {3,4,5,6,7};
    //先定义的数组分配在高地址
    printf("a = %p\n",a);
    printf("b = %p\n",b);
    for (int i = 0; i < 5; i++) {
        printf("&b[%d] = %p\n",i,&b[i]);
    }
    return 0;
}

数组传递地址注意

//  1.形参数组类型和长度要和实参一致
#include <stdio.h>
//这种写法可以:
//void print_arr(int arr[]){
//    for (int i = 0; i < 5; i++) {
//        printf("%d\t",arr[i]);
//    }
//}
//int main(int argc, const char * argv[]) {
//    int a[] = {1,2,3,4,5};
//    print_arr(a);
//    return 0;
//}
//这种写法错误1606416424  256 512 768 1024    这是下面的执行结果
//void print_arr(float arr[]){
//    for (int i = 0; i < 5; i++) {
//        printf("%d\t",arr[i]);
//    }
//}
//int main(int argc, const char * argv[]) {
//    int a[] = {1,2,3,4,5};
//    print_arr(a);
//    return 0;
//}

//关于数组名作为函数参数后,数组的长度信息丢失的问题
//C语言规定,不管什么类型的数据,数据的内存地址在内存中占用8字节。只要是地址
void print_arr2(int arr[]){//只传递过来首地址
    int len = sizeof(arr);//不轮什么类型所有的地址都占8个字节
    printf("arr2_len = %d\n",len);//8
}

//这种写法错误
// 地址传递是只传递名,不检查数组长度所以形参的数组长度可以与实参不一致,也可以不写数组长度

void print_arr(int arr[]){
    for (int i = 0; i < 5; i++) {
        printf("%d\t",arr[i]);
    }
}
int main(int argc, const char * argv[]) {
    int a[10] = {1,2,3,4,5,6,7,6,5,6};
    int len = sizeof(a);
    printf("a_len = %d\n",len);//40
    print_arr(a);
    print_arr2(a);
    return 0;
}
数组中的越界问题
char s[2] = {‘c’,’h’};
下表范围:0、1
s[2]=‘s’//越界下标越界了
如果越界的内存空间是空的,其他数组占用此空间时,会覆盖这个空间,还会发生未知错误,系统崩溃。
#include <stdio.h>

int main(int argc, const char * argv[]) {
    char s[2] = {'c','h'};//s[]数组下标范围是0-1
    printf("%c\n",s[0]);
    printf("%c\n",s[1]);
    printf("%c\n",s[2]);//此时是越界的,不安全的,这个空间不属于s[]数组的
    return 0;
}
数组元素作为函数参数
int a[4] = {1,2,3,4};
a[0]/a[1]/a[2]/a[3]就是数组元素
两种形式:
1.  把数组元素(下标变量)作为实参去使用
把作为实参的数组元素的值传递给形参,实现单向的值传递。
#include <stdio.h>

int sum(int x,int y){
    return x+y;
}
int main(int argc, const char * argv[]) {
    int a[5] = {1,2,3,4,5};
    //需求:要求计算数组第一个元素a[0]和最后一个元素a[4]的和
    //等同于传递了两个变量
    printf("sum = %d\n",sum(a[0],a[4]));
    return 0;
}
思考题1:
判别一个整数数组中各元素的值,若大于0则输出该值,若小于等于0则输出0.(判断过程用函数实现)
2.  把数组名作为函数的实参和形参去使用
要求形参和实参相应必须都是同类型数组
此时不是值传递,而是地址传递。
void change(int arr[2]){//相当于给a又起了个名字,没有新建内存空间
    printf("&arr = %p\n",arr);

}
int main(int argc, const char * argv[]) {
    int a[]={1,2};
    change(a);//数组名a也是数组的首地址
    printf("&a = %p\n",a);
    return 0;
}
冒泡排序:Bubble Sort
重复比较,一次比较两个元素,如果顺序错误就把他们交换过来
大数下沉:每一次让最大的数跑到最后面去
小数上浮:每一次让最小的数跑到最前面
#include <stdio.h>

/*!
 * @param arr 数组名
 * @param len 数组长度
 */
void paiXu(int arr[],int len){
    int temp;
    for (int i = 0; i < len - 1; i++) {
        for (int j = 0; j < len - 1 - i; j++) {
            if (arr[j] > arr[j+1]) {//重复比较,一次比较两个元素,如果顺序错误就把他们交换过来
                temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
    for (int i = 0; i < 10; i++) {
        printf("%d\t",arr[i]);
    }
}

int main(int argc, const char * argv[]) {
    int s[10] = {5,3,0,2,8,9,1,4,7,6};
    paiXu(s,10);
    return 0;
}
选择排序:
找到最小元素放到序列的起始位置,再找剩下的中最小的,依次摆放
#include <stdio.h>
void paiXu(int arr[],int len){
    int temp;
    for (int i = 0; i < len - 1; i++) {
        for (int j = i + 1; j < len; j++) {//先同旁边的比较,一直比较到最后面一个数
            if (arr[i] > arr[j]) {
                temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
    for (int i = 0 ; i < 10; i++) {
        printf("%d\t",arr[i]);
    }
}

int main(int argc, const char * argv[]) {
    int arr[10] = {10,4,23,8,97,2,3,1,8,-2};
    paiXu(arr, 10);
    return 0;
}
折半查找:
在有序表中,取中间元素作为比较对象,若给定值于中间元素的要查找数相等,则查找成功,值小于要查找的数,那么在中间左半区继续查找
若大于要查找的数,那么去右半区继续查找
//  折半查找效率最高
//条件是有序数组中查找

#include <stdio.h>
/*!
 *
 * @param arr 数组
 @param len 数组长度
 @param key 要查找的数
 *
 * @return 要查找的数的位置如果找不到返回-1
 *
 */
int mid_Find(int a[],int len,int key){
    int low = 0,mid,high = len-1;
    while (low <= high) {
        mid = (high + low) / 2;//数组中间位
        if (key > a[mid]) {
            low = mid + 1;//大于中间位的值则在右边区域找
        }else if (key < a[mid])
            high = mid - 1;//小于中间位的值则在左边区域找
        else
            return mid;
    }
    return -1;
}

int main(int argc, const char * argv[]) {
    // int三个变量high、low、mid,当这三个变量在数组的同一位置时,取得这个值,若没有则提示没有这个数字
    int arr[5] = {1,45,67,76,80};
    //          low     mid       high  (high+low)/2    >  num
    //          low     high
    int num = mid_Find(arr,5,4546);
    if (num == -1) {
        printf("查无次数\n");
    }
    printf("%d\n",arr[num]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值