IOS开发之路--C语言数组和字符串

概览

数组在C语言中有着特殊的地位,它有很多特性,例如它的存储是连续的,数组的名称就是数组的地址等。而在C语言中是没有String类型的,那么如果要表示一个字符串,就必须使用字符串数组。今天主要就介绍如下三个方面:

一维数组 多维数组 字符串

一维数组

一维数组操作比较简单,但是需要注意,数组长度必须是固定的,长度不能使用变量进行初始化;如果声明的同时进行赋值则数组长度可以省略,编译器会自动计算数组长度;同时数组不能先声明再一次性赋值(当然可以对每个元素一一赋值)。

#include <stdio.h>

int main(){
  int len = 2;
  //int a[len] = { 1, 2};//错误,不能使变量
  int a[2];//正确
  a[0] = 1;
  a[1] = 2;
  //a[2] = 3;//超过数组长度,但是编译器并不会检查,运行报错
  int b['a'] = {1,2,3};//'a'=97,所以可以作为数组长度,但是后面的元素没有初始化,其值默认为0
  for (int i = 0; i < 97; ++i){
    printf("b[%d]=%d\n",i,b[i]);
  }
  int c[2 * 3];//2*3是固定值可以作为数组长度
  int d[] = { 1, 2, 3 };//如果初始化的同时赋值则数组长度可以省略,当前个数为3
}

扩展--数组的存储

数组在内存中存储在一块连续的空间中,如果知道数组类型(int、float等)和初始地址就可以知道其他元素的地址,同时由于数组名等于数组第一个元素的地址,所以当数组作为参数(作为参数时形参可以省略)其实是引用传递。

#include <stdio.h>

int main(){
  int const l = 3;
  int a[l] = { 1, 2,3 };
  for (int i = 0; i < l; ++i){
    //由于当前在32位编译器下,int型长度为4个字节,可以判断出三个地址两两相差都是4
    printf("a[%d]=%d,address=%x\n", i, a[i], &a[i]);
  }
  /*当前输出结果:
  a[0] = 1, address = c9f95c
  a[1] = 2, address = c9f960
  a[2] = 3, address = c9f964*/
}

我们看一下上面定义的数组在内存中存储结构

再来看一下数组(注意不是数组的元素,是数组)作为参数传递的情况

#include <stdio.h>

void changeValue(int a[]){
  a[0] = 10;
}

int main(){
  int a[2] = {1,2};
  changeValue(a);
  for (int i = 0; i < 2; ++i){
    printf("a[%d]=%d\n",i,a[i]);
  }
  /*打印结果
  a[0]=10
  a[1]=2
  */
}

多维数组

多维数组其实可以看成是一个特殊的一维数组,只是每个元素又是一个一维数组,下面简单看一下多维数组的初始化和赋值

#include <stdio.h>

int main(){
  int a[2][3];//2行3列,二维数组可以看成是一个特殊的一维数组,只是它的每一个元素又是一个一维数组
  a[0][0] = 1;
  a[0][1] = 2;
  a[0][2] = 3;
  a[1][0] = 4;
  a[1][1] = 5;
  a[1][2] = 6;
  for (int i = 0; i < 2; ++i){
    for (int j = 0; j < 3; ++j){
      printf("a[%d][%d]=%d,address=%x\n", i, j, a[i][j], &a[i][j]);
    }
  }
  /*打印结果
  a[0][0]=1,address=f8fb24
  a[0][1]=2,address=f8fb28
  a[0][2]=3,address=f8fb2c
  a[1][0]=4,address=f8fb30
  a[1][1]=5,address=f8fb34
  a[1][2]=6,address=f8fb38
  */
  //初始化并直接赋值
  int b[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
  //由于数组的赋值顺序是先从第一行第一列,再第一行第二列...然后第二行第一列...,所以我们也可以写成如下形式
  int c[2][3] = { 1, 2, 3, 4, 5, 6 };
  //也可以只初始化部分数据,其余元素默认为0
  int d[2][3] = { 1, 2, 3, 4 };
  for (int i = 0; i < 2; ++i){
    for (int j = 0; j < 3; ++j){
      printf("d[%d][%d]=%d\n", i, j, d[i][j]);
    }
  }
  /*打印结果
  d[0][0]=1
  d[0][1]=2
  d[0][2]=3
  d[1][0]=4
  d[1][1]=0
  d[1][2]=0
  */
  //当然下面赋值也可以
  int e[2][3] = { {}, { 4, 5, 6 } };
  //可以省略行号,但是绝对不可以省略列号,因为按照上面说的赋值顺序,它无法判断有多少行
  int f[][3] = { {1,2,3},{4,5,6} };
}

扩展--多维数组的存储

以上面a数组为例,它在内存中的结构如下图

根据上图和一维数组的存储,对于二维数组可以得出如下结论:数组名就是整个二维数组的地址,也等于第一行数组名的地址,还等于第一个元素的地址;第二行数组名等于第二行第一个元素的地址。用表达式表示:

a=a[0]=&a[0][0] a[1]=&a[1][0]

关于多维数组,其实可以以此类推,在此不再赘述。

字符串

在C语言中是没有字符串类型的,如果要表示字符串需要使用char类型的数组,因为字符串本身就是多个字符的组合。但是需要注意的是字符串是一个特殊的数组,在它的结束位置必须要加一个”\0”(ASCII中0是空操作符,表示什么也不做)来表示字符串结束,否则编译器是不知道什么时候字符串已经结束的。当直接使用字符串赋值的时候程序会自动加上”\0”作为结束符。

//
// main.c
// ArrayAndString
//
// Created by KenshinCui on 14-7-06.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#include <stdio.h>

int main(int argc, const char * argv[])
{

  char a[] = {'K','e','n','s','h','i','n','\0'};
  printf("%s",a); //结果:Kenshin,注意使用%s输出字符串内容,如果换成整形输出格式其实输出的是a的地址
  printf("\n");
  printf("address=%x", a); //结果:address=5fbff890
  printf("\n");
  //后面的\0绝对不能省略,如果没有\0则会出现如下情况
  char b[] = { 'I', 'a', 'm'};
  printf("%s",b); //没有按照期望输出,多了一些垃圾数据,在当前环境打印结果:IamKenshin
  printf("\n");
  printf("address=%x",b); //结果:address=5fbff88d
  printf("\n");
  //直接赋值为字符串,此时不需要手动添加\0,编译器会自动添加
  char c[] = "Kenshin";
  printf("c=%s",c); //结果:c=Kenshin
  printf("\n");

  //二维数组存储多个字符串
  char d[2][3]={"Kenshin","Kaoru","Rose","Jack","Tom","Jerry"};

  return 0;
}

从上面代码注释中可以看到打印b的时候不是直接打印出来“Iam”而是打印出了“IamKenshin”,原因就是编译器无法判断字符串是否结束,要解释为什么打印出“IamKenshin”我们需要了解a和b在内存中的存储。

从图中我们不难发现由于a占用8个字节,而定义完a后直接定义了b,此时分配的空间连续,b占用3个字节,这样当输出b的时候由于输出完“Iam”之后并未遇到”\0”标记,程序继续输出直到遇到数组a中的“\0”才结束,因此输出内容为“IamKenshin”。

扩展--字符串操作常用函数

下面简单看一下和字符和字符串相关的常用的几个函数

//
// main.c
// ArrayAndString
//
// Created by Kenshin Cui on 14-7-04.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#include <stdio.h>

int main(int argc, const char * argv[])
{
  /*字符操作*/
  putchar('a'); //结果:a,putchar一次只能输出一个字符
  printf("\n");
  putchar(97);//结果:a
  printf("\n");
  char a;
  a=getchar();//getchar()一次只能接收一个字符,可以接收空格、tab、回车
  printf("a=%c",a);
  printf("\n");

  /*字符串操作*/
  char b[]="Kenshin";
  printf("b=%s",b);
  printf("\n");
  puts(b); //puts用于输出单个字符串,不能像printf格式化输出,会自动添加换行
  printf("\n");

  char c[10];
  scanf("%s",c);//注意c没必要写成&c,因为c本身就代表了数组的地址
  printf("c=%s\n",c);//注意即使你输入的内容大于10,也能正确输出,但是下面的gets()函数却不行
  printf("\n");

  //gets()函数,注意它是不安全的,因为接收的时候不知道它的大小容易造成溢出,建议不要使用
  char d[10];
  gets(d); //gets一次只能接收一个字符串,但是scanf可接收多个;scanf不能接收空格、tab,gets则可以
  printf("d=%s",d);
  printf("\n");

  char e[]={'K','s','\0'};
  printf("%lu",strlen(e)); //结果是:2,不是3,因为\0不计入长度
  printf("\n");
  char f[]={"Kenshin"};
  printf("%lu",strlen(f)); //结果是:7
  printf("\n");

  char g[5];
  strcpy(g,"hello,world!");
  printf("%s",g); //结果是:hello,即使定义的g长度为5,但是也能完全拷贝进去
  printf("\n");
  char h[5];
  char i[]={'a','b','c','\0','d','e','f','\0'};
  strcpy(h,i);
  printf("%s",h); //结果是:abc,遇到第一个\0则结束
  printf("\n");

  strcat(i,"ghi");
  printf("%s",i); //结果是:abcghi,注意不是abcdefghi,strcat,从i第一\0开始使用“ghi”覆盖,覆盖完之后加上一个\0,在内存中目前应该是:{'a','b','c','g','h','i','\0','f','\0'}
  printf("\n");

  char j[]="abc";
  char k[]="aBc";
  char l[]="acb";
  char m[]={'a','\0'};
  printf("%d,%d,%d",strcmp(j,k),strcmp(k,l),strcmp(l,m));//遇到第一个不相同的字符或\0则返回两者前后之差,结果:32,-33,99
  printf("\n");

  return 0;
}

注意在Xcode中会提示gets是不安全的,因为Xcode使用的是gcc编译器,在gcc编译器中已经不能正确编译gets()函数,推荐使用fgets()。

(0)

相关推荐

  • iOS开发之时间戳(或date)转字符串的实例代码

    1.时间戳转字符串 ///时间戳转化为字符转0000-00-00 00:00 + (NSString *)time_timestampToString:(NSInteger)timestamp{ NSDate *confromTimesp = [NSDate dateWithTimeIntervalSince1970:timestamp]; NSDateFormatter *dateFormat=[[NSDateFormatter alloc]init]; [dateFormat setDate

  • iOS时间字符串格式化输出技巧详解

    一.前言 最近项目开发过程中用到了大量的关于时间的处理,将后台返回的时间字符串转换为指定的格式时间再显示在UI上. 例如: 将后台返回的时间字符串2017-04-16 13:08:06转换为:2017年04月16日.2017年04月.04月16日.2017-04-16.2017-04.04-16.13:08.星期几等等. 项目是多人开发,由于前期没有统一处理时间转换的问题,后期发现项目中好多关于时间转换的代码,大部分都是通过(- : 等字符)截取成字符串数组再取相应时间拼接成指定格式,输出在UI

  • iOS开发支付宝支付成功返回字符串的处理操作

    { memo=""; result="partner=\"311811\"&seller_id=\"nse@gmail.com\"&out_trade_no=\"S005372\"&subject=\"\U522b\U5885\U8ba2\U5355\"&body=\"\U5885\"&total_fee=\"0.1\"

  • iOS中时间与时间戳的相互转化实例代码

    本人搜索了很多关于iOS中时间与时间戳的相互转化的资料,下面我来记录一下,有需要了解iOS中时间与时间戳的相互转化的朋友可参考.希望此文章对各位有所帮助. //获取当前系统时间的时间戳 #pragma mark - 获取当前时间的 时间戳 +(NSInteger)getNowTimestamp{ NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateStyle:NSDateFormatterM

  • IOS判断字符串是不是纯数字的方法总结

    前言 在大家开发项目的时候,遇到需求可能是让我们只输入一段纯数字,这时候我们就要对这个字符串进行筛选判断,不符合纯数字进行提示操作,以求达到最好的交互效果也能满足需求. 下面介绍几种判断字符串是否为纯数字的方法 第一种方式是使用NSScanner: 1. 整形判断 - (BOOL)isPureInt:(NSString *)string{ NSScanner* scan = [NSScanner scannerWithString:string]; int val; return [scan s

  • IOS 时间和时间戳之间转化示例

    以毫秒为整数值的时间戳转换 时间戳转化为时间NSDate - (NSString *)timeWithTimeIntervalString:(NSString *)timeString { // 格式化时间 NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; formatter.timeZone = [NSTimeZone timeZoneWithName:@"shanghai"]; [formatter setDa

  • iOS中使用MD5加密字符串

    1,新建NSString的分类,记得添加加密所需的头文件#import <CommonCrypto/CommonDigest.h> , NSString+MD5.h: #import <Foundation/Foundation.h> #import <CommonCrypto/CommonDigest.h> @interface NSString (MD5) + (NSString *)md5To32bit:(NSString *)str; @end 2,编写加密方法

  • IOS用AFN发送字符串形式的Json数据给服务器实例

    每个人遇到后台的需求不一样,我只能写出自己目前遇到的需求和做法,我的后台是需要一个Json的key,对应一个字符串类型的字典,后台要求的是带双引号和冒号的字典,所以就拼接了一下 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; // 发送post请求 // manager.responseSerializer = [AFJSONResponseSerializer serializer]; manager.respon

  • iOS获取当前时间和当前时间戳的方法

    //获取当前的时间 +(NSString*)getCurrentTimes{ NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; // ----------设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制 [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; //现在时间,你可以输出来看下是什么格式 NSDate *datenow = [NSDate d

  • IOS开发之路--C语言数组和字符串

    概览 数组在C语言中有着特殊的地位,它有很多特性,例如它的存储是连续的,数组的名称就是数组的地址等.而在C语言中是没有String类型的,那么如果要表示一个字符串,就必须使用字符串数组.今天主要就介绍如下三个方面: 一维数组 多维数组 字符串 一维数组 一维数组操作比较简单,但是需要注意,数组长度必须是固定的,长度不能使用变量进行初始化:如果声明的同时进行赋值则数组长度可以省略,编译器会自动计算数组长度:同时数组不能先声明再一次性赋值(当然可以对每个元素一一赋值). #include <stdi

  • IOS开发之路--C语言基础知识

    概览 当前移动开发的趋势已经势不可挡,这个系列希望浅谈一下个人对IOS开发的一些见解,这个IOS系列计划从几个角度去说IOS开发: C语言 OC基础 IOS开发(iphone/ipad) Swift 这么看下去还有大量的内容需要持续补充,但是今天我们从最基础的C语言开始,C语言部分我将分成几个章节去说,今天我们简单看一下C的一些基础知识,更高级的内容我将放到后面的文章中. 今天基础知识分为以下几点内容(注意:循环.条件语句在此不再赘述): Hello World 运行过程 数据类型 运算符 常用

  • IOS开发之路--C语言指针

    概览 指针是C语言的精髓,但是很多初学者往往对于指针的概念并不深刻,以至于学完之后随着时间的推移越来越模糊,感觉指针难以掌握,本文通过简单的例子试图将指针解释清楚,今天的重点有几个方面: 什么是指针 数组和指针 函数指针 什么是指针 存放变量地址的变量我们称之为"指针变量",简单的说变量p中存储的是变量a的地址,那么p就可以称为是指针变量,或者说p指向a.当我们访问a变量的时候其实是程序先根据a取得a对应的地址,再到这个地址对应的存储空间中拿到a的值,这种方式我们称之为"直接

  • IOS开发之路--C语言存储方式和作用域

    概述 基本上每种语言都要讨论这个话题,C语言也不例外,因为只有你完全了解每个变量或函数存储方式.作用范围和销毁时间才可能正确的使用这门语言.今天将着重介绍C语言中变量作用范围.存储方式.生命周期.作用域和可访问性. 变量作用范围 存储方式 可访问性 变量作用范围 在C语言中变量从作用范围包括全局变量和局部变量.全局变量在定义之后所有的函数中均可以使用,只要前面的代码修改了,那么后面的代码中再使用就是修改后的值:局部变量的作用范围一般在一个函数内部(通常在一对大括号{}内),外面的程序无法访问它,

  • IOS开发之路--C语言构造类型

    概述 在第一节中我们就提到C语言的构造类型,分为:数组.结构体.枚举.共用体,当然前面数组的内容已经说了很多了,这一节将会重点说一下其他三种类型. 结构体 枚举 共用体 结构体 数组中存储的是一系列相同的数据类型,那么如果想让一个变量存储不同的数据类型就要使用结构体,结构体定义类似于C++.C#.Java等高级语言中类的定义,但事实上它们又有着很大的区别.结构体是一种类型,并非一个变量,只是这种类型可以由其他C语言基本类型共同组成. // // main.c // ConstructedType

  • IOS开发之路--C语言预处理

    概述 大家都知道一个C程序的运行包括编译和链接两个阶段,其实在编译之前预处理器首先要进行预处理操作,将处理完产生的一个新的源文件进行编译.由于预处理指令是在编译之前就进行了,因此很多时候它要比在程序运行时进行操作效率高.在C语言中包括三类预处理指令,今天将一一介绍: 宏定义 条件编译 文件包含 宏定义 对于程序中经常用到的一些常量或者简短的函数我们通常使用宏定义来处理,这样做的好处是对于程序中所有的配置我们可以统一在宏定义中进行管理,而且由于宏定义是在程序编译之前进行替换相比定义成全局变量或函数

  • IOS开发基础之二维数组详解

    IOS开发基础之二维数组详解 首先我们知道OC中是没有二维数组的,二维数组是通过一位数组的嵌套实现的,但是别忘了我们有字面量,实际上可以和C/C++类似的简洁地创建和使用二维数组.这里总结了创建二维数组的两种方法以及数组的访问方式. 通过字面量创建和使用二维数组(推荐) // 1.字面量创建二维数组并访问(推荐) NSArray *array2d = @[ @[@11,@12,@13], @[@21,@22,@23], @[@31,@32,@33] ]; // 字面量访问方式(推荐) NSLog

  • IOS开发之判断两个数组中数据是否相同实例详解

    IOS开发之判断两个数组中数据是否相同实例详解 前言: 工作中遇到的问题,这里记录下,也许能帮助到大家 实例代码: NSArray *array1 = [NSArray arrayWithObjects:@"a", @"b", @"c", nil nil]; NSArray *array2 = [NSArray arrayWithObjects:@"b", @"a", @"c", nil

  • iOS开发基础之C语言

    为何学习iOS开发要先学C语言呢,学习c语言对ios开发有何作用. 现在越来越多的iOS开发兴趣爱好者投入到了iOS培训中,有的是已经在职的员工,有的是还在就读的学生,还有一些是完全零基础的同学,那么对于他们来说就要一切从基础开始学,首先从C语言学起. 因为C语言是一门语言基础,因具备简洁.灵活等特点而被广泛应用,在多种开发环境中都起着重要作用.那么,为什么学习iOS开发要先学C语言呢? 因为在iOS开发中,会经常使用C语言和汇编的,而汇编语言相对而言要生涩繁琐些,C语言因此便成为程序员的首选.

  • iOS开发之路--微博“更多”页面

    最终效果图: MoreViewController.m // // MoreViewController.m // 20_帅哥no微博 // // Created by beyond on 14-8-4. // Copyright (c) 2014年 com.beyond. All rights reserved. // #import "MoreViewController.h" @interface MoreViewController () { // more.plist根是字典

随机推荐