C语言中数组的一些基本知识小结_C 语言

初始化数组

int ages[3] = {4, 6, 9};
int nums[10] = {1,2}; // 其余的自动初始化为0
int nums[] = {1,2,3,5,6}; // 根据大括号中的元素个数确定数组元素的个数
int nums[5] = {[4] = 3,[1] = 2}; // 指定元素个数,同时给指定元素进行初始化
int nums[3]; nums[0] = 1; nums[1] = 2; nums[2] = 3; // 先定义,后初始化

定义但是未初始化,数组中有值,但是是垃圾值。
对于数组来说,一旦有元素被初始 化,其他元素都被赋值0。
计算数组中元素的个数

int count = sizeof(数组) / sizeof(数组[0]) // 数组的长度 = 数组占用的总字节数 / 数组元素占用的字节数

数组注意事项

在定义数组的时候[]里面只能写整型常量或者是返回整型常量的表达式。

int ages['A'] = {19, 22, 33};

printf("ages[0] = %d\n", ages[0]);

int ages[5 + 5] = {19, 22, 33};

printf("ages[0] = %d\n", ages[0]);

int ages['A' + 5] = {19, 22, 33};

printf("ages[0] = %d\n", ages[0])

错误写法。

没有指定元素个数(int nums[] = {1,2,3,5,6}; 这样是可以的,但是如果先声明,并没有初始化,则是错误的)

int a[]; // 错误

[]中不能放变量

int number = 10;

int ages[number]; // 不报错, 但是没有初始化, 里面是随机值
  > int number = 10;
  >
  > int ages[number] = {19, 22, 33} // 直接报错

 - > int ages10[5];
  >
  > ages10 = {19, 22, 33};  // 错误。只能在定义数组的时候进行一次性(全部赋值)的初始化

  - 访问数组越界。

数组的内存分配:

变量在内存中是从大到小寻址的(内存中以字节为单位),比如00000000 00000000 00000000 00001010在内存中,00001010的地址是最小的;而数组则有些不同,数组的元素自然的从上往下排列 存储,整个数组的地址为首元素的地址。 (但是组成元素的字节还是按从大到小)

注意:字符在内存中是以对应ASCII值的二进制形式存储的,而非上表的形式。 在这个例子中,数组x的地址为它的首元素的地址0x08,数组ca的地址为0x03。
注意数组越界问题,越界会访问到其他内容(比如有两个数组在内存中挨着,第一个数组越界可能会访问到第二个数组的元素),甚至会让程序崩溃。

当数组名作为函数参数时, 因为自动转换为了指针类型,所以在函数中无法动态计算除数组的元素个数。

在64位编译器下,指针类型默认为8个字节。

有的时候我们可能想要在一个函数里面动态计算数组的个数,所以可能会这么做:

void printMyArray(int myArray[]) {
   int length = sizeof(myArray) / sizeof(myArray[0]);
   for(int i = 0; i < length; i++) {
    printf("%i", myArray[i]);
   }
}

int main() {
  int myArray[5] = {1,2,3,4,5};
  printMyArray(myArray);
  return 0;
}

可以看到在printMyArray函数中我们动态计算传进来的数组的个数,但是结果是错误的,因为它只能输出前两个数。

这是因为,在把数组当成函数的参数的时候,数组会被认为成指针,所以是8个字节,所以计算出的length是2,所以只能输出前两个数字。

解决:我们需要给出一个新的参数来获得length,在main()里面计算好length然后传入printMyArray。

void printMyArray(int myArray[], int length) {
  for(int i = 0; i < length; i++) {
    printf("%i ", myArray[i]);
  }
}

int main(int argc, const char * argv[]) {
  int myArray[5] = {1,2,3,4,5};
  int length = sizeof(myArray) / sizeof(myArray[0]);
  printMyArray(myArray, length);
  return 0;
}

“填坑法”的思想:

比如给出这样一题。要求从键盘输入6个0~9的数字,排序后输出。

做法有很多,”填坑法”的意思就是首先定义一个10个数的数组(0~9),初始化都为0。

接着接受用户的输入(可以用for循环),关键的一步是,将用户输入的值作为数组的下标,将这个下标所对应的值改为1(填坑),再接着for循环输出数组中值是1的索引。

// 空间换时间, 适合数据比较少
//  1.定义数组,保存用户输入的整数
//  一定要给数组初始化, 否则有可能是一些随机值
  int numbers[10] = {0};
//  2.接收用户输入的整数
//  2.1定义变量接收用户输入的整数
  int index = -1;
  for (int i = 0; i < 6; i++) {
    printf("请输入第%d个整数\n", i + 1);
    scanf("%d", &index);
//    将用户输入的值作为索引取修改数组中对应的元素的值为1
//    指针的时候回来演示刚才的问题
    numbers[index] = 1 ;
  }

  int length = sizeof(numbers) / sizeof(numbers[0]);
  for (int i = 0; i < length; i++) {
    if (1 == numbers[i]) {
      // 输出索引
      printf("%d", i);
    }
  }

这个做法的要点是数组中的初始值都为0,而数组的索引和用户输入的数字是一一对应的,所以只需要将用户输入的数字相对应的索引的元素改成1,然后再for循环输出的话相当于有序输出,最后得到结果。

但是这种做法是有问题的,比如用户输入了重复的数字,但是上面的做法只能将相同的数字输出一次。我们的做法是将相同索引的元素的数字累加,之后再增加一层循环来进行输出。

//  1.定义数组,保存用户输入的整数
  int numbers[10] = {0};
//  2.接收用户输入的整数
//  2.1定义变量接收用户输入的整数
  int index = -1;
  for (int i = 0; i < 6; i++) {
    printf("请输入第%d个整数\n", i + 1);
    scanf("%d", &index);
//    将用户输入的值作为索引取修改数组中对应的元素的值为1
//    假设 用户输入的是 1,1,1,2,2,2
    numbers[index] = numbers[index] + 1 ;
  }

  int length = sizeof(numbers) / sizeof(numbers[0]);
  for (int i = 0; i < length; i++) {
//    j = 1 因为如果数组元素中存储的值是0不用输出
//    将i对应存储空间中的元素取出,判断需要输出几次
    for (int j = 1; j <= numbers[i]; j++) {
      printf("%d", i);// 1 1 1 2 2 2
    }
  }

选择排序

主要思想就是,基本上默认数组中第一个元素为最大(最小)值,之后将这个元素和后面的每个元素都进行比较,以由大到小排序为例,当第一个值遇到比其大的,就进行交换。这样第一轮过后,第一位就是最大的。接着进行第二轮,由第二个数开始逐个比较,遇到比第二个数大的进行交换,这样第二轮之后第二个数就是第二大的了,以此类推,不断进行选择,最后完成排序。

void selectSort(int numbers[], int length) {
  for (int i = 0; i < length; i++) {
    for (int j = i + 1; j < length; j++) {
      if (numbers[i] < numbers[j]) {
        int temp = numbers[i];
        numbers[i] = numbers[j];
        numbers[j] = temp;
      }
    }
  }
}

int main(int argc, const char * argv[]) {
  int myArray[] = {42, 7, 1, -3, 88};
  int length = sizeof(myArray) / sizeof(myArray[0]);
  selectSort(myArray, length);
  for (int i = 0; i < length; i++) {
    printf("%i ", myArray[i]);
  }
  return 0;
}

在写的时候可以这样想:当第一个数来比较的时候,i = 0,那么j应该等于i + 1,因为第一个数要和第二个数开始比,并且比较length - 1次;当i = 1时,j = 2,并且比较length - 2次,以此类推;上面写的是由大到小排序。

冒泡排序

主要思想是两个相邻的元素进行比较,以由小到大排序为例,那么由第一个元素开始和第二个比较,如果第一个比第二个大,那么就进行交换;然后进行第二个和第三个元素的比较,以此类推,第一轮之后,那么数组的最后一个元素就是最大的,以此类推。

void bubbleSort(int numbers[], int length) {
  for (int i = 0; i < length - 1; i++) {
    for (int j = 0; j < length - i - 1; j++) {
      if (numbers[j] > numbers[j + 1]) {
        int temp = numbers[j];
        numbers[j] = numbers[j + 1];
        numbers[j + 1] = temp;
      }
    }
  }
}

int main(int argc, const char * argv[]) {
  int myArray[] = {42, 7, 1, -3, 88};
  int length = sizeof(myArray) / sizeof(myArray[0]);
  bubbleSort(myArray, length);
  for (int i = 0; i < length; i++) {
    printf("%i ", myArray[i]);
  }
  return 0;
}

注意这里和选择排序不同的是,比较的并非numbers[i]和numbers[j],而是比较的numbers[j]和numbers[j+1],而外层循环的i代表比较的轮数,内层循环才是真正的每一轮进行的比较。这里是由小到大排序。

折半查找

折半查找顾名思义,我们找到数组的最大值max,最小值min求出中间值mid,然后用mid作为数组下标得到对应的元素,用这个元素和目标值key进行比较:

如果numbers[mid] > key,那么说明key在min和mid之间,那么就设置max为mid - 1,min不变,然后重新计算mid,重复上述步骤,最后找出key。

如果numbers[mid] < key,那么说明key在mid和max之间,那么就设置min为mid + 1,max不变,然后重新计算mid,重复上述步骤,最后找出key。

注意这里的结束条件,有可能数组中有这个key,也有可能没有,那么当min > max时,说明数组中并没有这个key,要小心这种情况。

折半查找要求数组必须是有序的。(有序表)

int binSearch(int myArray[], int length, int key) {
  int index = -1;

  int max = length - 1;
  int min = 0;
  int mid = (max + min) / 2;

  while (min <= max) {
    if (myArray[mid] > key) {
      max = mid - 1;
    } else if (myArray[mid] < key){
      min = mid + 1;
    } else if (myArray[mid] == key) {
      index = mid;
      break;
    }
    mid = (max + min) / 2;
  }

  return index;
}

int main(int argc, const char * argv[]) {
  int myArray[] = {-3, 1, 7, 42, 88};
  int length = sizeof(myArray) / sizeof(myArray[0]);
  int index = binSearch(myArray, length, 88);
  printf("index: %i ", index);
  return 0;
}

首先我假设index = -1,表示没有相应的值。接着获取max,min,mid的值,注意while循环的条件,在这里我用的是当min <= max的时候循环,当min > max时候跳出循环,说明并未找到key的值。在循环体里面,像刚才分析的那样判断,当myArray[mid] == key的时候说明我们找到了这个值,那么将index设置成找到值的下标,然后跳出循环。如果未找到值则index = -1。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索c语言
数组
c语言数组排序小结、c语言实验小结、c语言实训小结、c语言课程设计小结、c语言程序设计小结,以便于您获取更多的相关知识。

时间: 2024-09-22 03:45:03

C语言中数组的一些基本知识小结_C 语言的相关文章

一些C语言中字符串的算法问题解决实例小结_C 语言

    字符串问题是面试中经常出现的问题,这类问题有很多,难以不一.下面是几道字符串的题目,网上都能找到解答,自己实现了一下,供网友参考.感觉算法重要的是要有正确的思路,实现起来不是问题.自己一定要多思考,这样收获可能会更多一点.         问题1:找两个字符串的最长公共子串.         具体描述,如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中,则字符串一称之为字符串二的子串.注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中.请编写一个函数,输入两个字

C语言中的各种文件读写方法小结_C 语言

前言    找工作的时候,曾经用C语言练习过一段时间的算法题目,也在几个还算出名的OJ平台有过还算靠谱的排名.之前以为C语言只限于练习一下算法,但是工作中的一个问题解决让我意识到C语言的用处还是非常广泛的.下面介绍一下,如果用C语言来操作文件保存一个字符串,和读取一个字符串.算法中往往都是printf来打印出结果,但是真实工作中往往通过文件来进行一些持久化的存储工作. C-File I/O    文件的I/O操作是每一门语言的重点,因此这里我先来介绍一下如何用C语言去进行文件的I/O操作. 文件

C语言中压缩字符串的简单算法小结_C 语言

应用中,经常需要将字符串压缩成一个整数,即字符串散列.比如下面这些问题: (1)搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节.请找出最热门的10个检索串. (2)有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M.返回频数最高的100个词. (3)有10个文件,每个文件1G,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复.要求你按照query的频度排序. (4)给定a.b两个文件

C语言中获取文件状态的相关函数小结_C 语言

C语言stat()函数:获取文件状态头文件: #include <sys/stat.h> #include <unistd.h> 定义函数: int stat(const char * file_name, struct stat *buf); 函数说明:stat()用来将参数file_name 所指的文件状态, 复制到参数buf 所指的结构中. 下面是struct stat 内各参数的说明: struct stat { dev_t st_dev; //device 文件的设备编号

简单总结C语言中各种类型的指针的概念_C 语言

C语言中有很多关于指针的使用,指针也是C语言的灵魂所在,而且C语言中也有很多有关指针的概念,这里学习并总结了一些知道的概念.  常量指针:首先它是一个指针,常量只是用来修饰指针的定语.其定义如下: char const * cp; char a='a'; 如何识别呢?根据右结合优先,先是*优先,所以这个cp变量是一个指针,然后是const修饰*,所以这是一个常量指针.即指向常量的指针. cp=&a; //正常语法 *cp=a; //错误语法,因为其指向的值是一个常量  指针常量:首先它是一个常量

C语言中的函数指针基础学习教程_C 语言

顾名思义,函数指针就是函数的指针.它是一个指针,指向一个函数.看例子: A) char * (*fun1)(char * p1,char * p2); B) char * *fun2(char * p1,char * p2); C) char * fun3(char * p1,char * p2); 看看上面三个表达式分别是什么意思? C)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型. B) 也很简单,与C)表达式相比,唯一不同的就是函数的

C语言 指针数组详解及示例代码_C 语言

如果一个数组中的所有元素保存的都是指针,那么我们就称它为指针数组.指针数组的定义形式一般为: dataType *arrayName[length]; [ ]的优先级高于*,该定义形式应该理解为: dataType *(arrayName[length]); 括号里面说明arrayName是一个数组,包含了length个元素,括号外面说明每个元素的类型为dataType *. 除了每个元素的数据类型不同,指针数组和普通数组在其他方面都是一样的,下面是一个简单的例子: #include <stdi

C语言中逻辑运算符与条件运算符的学习教程_C 语言

逻辑运算符 逻辑运算符,用于对包含关系运算符的表达式进行组合,形成新的表达式:结果也是只有真或假两种情况,结果值用 BOOL 类型变量存储. 运算符 解释 结合方式 () [] -> . 括号(函数等),数组,两种结构成员访问 由左向右 ! ~ ++ -- + -  * & (类型) sizeof 否定,按位否定,增量,减量,正负号, 间接,取地址,类型转换,求大小 由右向左 * / % 乘,除,取模 由左向右 + - 加,减 由左向右 << >> 左移,右移 由左向

详解C语言中的#define宏定义命令用法_C 语言

#define命令#define定义了一个标识符及一个串.在源程序中每次遇到该标识符时,均以定义的串代换它.ANSI标准将标识符定义为宏名,将替换过程称为宏替换.命令的一般形式为: #define identifier string 注意: 1.该语句没有分号.在标识符和串之间可以有任意个空格,串一旦开始,仅由一新行结束. 2.宏名定义后,即可成为其它宏名定义中的一部分. 3.宏替换仅仅是以文本串代替宏标识符,前提是宏标识符必须独立的识别出来,否则不进行替换.例如: #define XYZ th