11.C语言提高(一)

1.排序

形参中的数组,编译器会把他当作指针处理
形参写在函数上,和写在函数内是一样的,只不过是
写在函数上具有对外的属性

2.关于数组地址

看下面函数的运行结果,你会发现,b+1和&b+1的区别,b表示的是数组元素首地址,所以b+1就是将从首元素向后移动一个元素后得到的第二个元素的地址,但是&b+1的结果优点出乎意料,它相对于首元素地址向后移动了40个位置,而40刚好是数组b的长度,怎么解释呢,其实就是&b表示的是整个数组的地址,把整个数组当作一个整体,那么加一就是移动这样一个整体后的地址了

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void main() {
    int b[10];
    printf("b:%d,b+1:%d,&b+1:%d", b, b + 1, &b + 1);
    system("pause");
}
打印结果:
b:19922588,b+1:19922592,&b+1:19922628请按任意键继续. . .

1)数组首元素的地址和数组地址是两个不同的概念
2)数组名代表数组首元素地址,他是个常量
解释如下:变量本质是内存空间的别名,而数组在定义时就会分配内存,内存就固定了,所以数组名起名以后就不能更改了
3)数组首元素的地址和数组值相等
C语言规定:
int a[10]
&a表示整个数组的地址,a表示数组首元素的地址,区别体现在地址+1的结果

如何定义一个数组数据类型
int a;//定义了一个int类型a
typedef int (MyArrayType)[5];//定义一个数组数据类型MyArrayType,
MyArrayType myArray;    //相当于int myArray[5]
myArray[0] = 0;
...
myArray[4]=4;
定义数组指针的第一种方法
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void main() {
    char *MyArray[] = {"1111","2222","3333"};
    //数组指针,一个指针,指向了数组

    //定义了一个数组数据类型
    typedef int(MyArrayType)[5];

    int i = 0;

    //用类型定义变量,相当于int myArray[5]
    MyArrayType myArray;

    //定义一个指针变量,这个变量指向数组
    MyArrayType *pArray;

    //定义一个数组,相当于一级指针
    int myArray2[5];

    //数组指针指向这个数组,相当于二级指针
    pArray = &myArray2;

    for (i = 0; i < 5; i++) {
        (*pArray)[i] = i + 1;
    }

    for (i = 0; i < 5; i++) {
        printf("%d", (*pArray)[i]);
    }
    system("pause");
}
定义数组指针的第二种方法
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void main() {
    //定义声明一个数组指针类型
    typedef int(*PArrayType)[5];
    //告诉编译器给我分配一个指针变量
    PArrayType pArray;

    //定义一个数组,相当于一级指针
    int myArray2[5];

    //数组指针指向这个数组,相当于二级指针
    pArray = &myArray2;
    

    int i = 0;

    for (i = 0; i < 5; i++) {
        (*pArray)[i] = i + 1;
    }

    for (i = 0; i < 5; i++) {
        printf("%d", (*pArray)[i]);
    }
    system("pause");
}
定义数组指针的第三种方法
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void main() {
    //直接定义一个指向数组的数组指针变量
    int(*PArrayType)[5];

    //定义一个数组,相当于一级指针
    int myArray2[5];

    //数组指针指向这个数组,相当于二级指针
    PArrayType = &myArray2;
    

    int i = 0;

    for (i = 0; i < 5; i++) {
        (*PArrayType)[i] = i + 1;
    }

    for (i = 0; i < 5; i++) {
        printf("%d", (*PArrayType)[i]);
    }
    system("pause");
}
3.内存四区的建立流程
内存四驱的建立流程.png
4.写一段程序证明栈的生长方向(开口向上还是开口向下)

在栈内存中定义两个变量ab一个数组buf,比较他们的地址。如图所示,如果栈的开口向上,那么先入栈的变量地址会小于后入栈的变量地址,如果开口向下则反之,所以可以根据这个特性来判断,我们打印了ab的地址,结果是a地址大于b,那么可以确定当前环境下,栈开口是向下的,可以默认栈的开口是向下的,这种情况比较多。
同时可以看到我们定义了一个数组,可以看到,虽然栈开口向下,但是数组中元素的存储方式并没有像栈中元素ab一样,你在栈开口向上的情况下试一下会发现,栈的开口不影响数组元素的存储形式,数组存储永远是图中所示的样子


栈属性.png
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void main() {
    int a;
    int b;
    printf("&a:%d,&b:%d\n", &a, &b);
    char buf[2] = {'a','b'};
    printf("&buf[0]:%d,&buf[1]:%d\n", &buf[0], &buf[1]);
    system("pause");
}
打印结果
&a:8387696,&b:8387684
&buf[0]:8387672,&buf[1]:8387673
请按任意键继续. . .
5.strcpy函数的5中推演方式
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/*
移动from和to指针,当from指针到达末尾的时候跳出
*/
void copy1(char *from, char *to) {
    for (; *from != '\0'; from++, to++) {
        *to = *from;
    }
    //在字符串的末尾加上\0,因为拷贝的时候跳过了\0
    *to = '\0';
    return;
}

/*
    把自增运算放在了循环中,++优先级大于*
    但是因为++是放在后边的,所以整体执行顺序还是先
    将*from赋值给*to,然后from和to做自增运算
*/
void copy2(char *from, char *to) {
    for (; *from != '\0';) {
        *to++ = *from++;
    }
    *to = '\0';
    return;
}

/*
    这种写法可以减少手动在末尾添加0的操作,
    (*to = *from) != '\0'这行代码做了两部操作
    第一先赋值,第二判断是否是0,所以当到达末尾
    得的时候,0也被拷贝了
*/
void copy3(char *from, char *to) {
    while ((*to = *from) != '\0') {
        from++;
        to++;
    }
}

/*
   这个操作更加简化,所以操作写在了判断条件中
*/
void copy4(char *from, char *to) {
    while ((*to++ = *from++) != '\0') {
        
    }
}

/*
最简版
*/
void copy5(char *from, char *to) {
    while (*to++ = *from++) {

    }
}
void main() {
    char *from = "hello world";
    char to[100];

    copy5(from, to);

    //C语言打印数据会将数组元素打印出来
    printf("to:%s\n", to);
    system("pause");
}
6.字符串反转的两种方式
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

//两头堵模型实现字符串反转
void inverse1(char *str) {
    int length;
    char *start;
    char *end;
    length = strlen(str);
    start = str;
    end = str + length - 1;

    while (start < end) {
        char c = *start;
        *start = *end;
        *end = c;
        ++start;
        --end;
     }
}

/*
递归调用实现字符串反转,这一点利用了栈的结构特点,先入后出
不断的将字符串中每一个字符入栈,最后打印每一个字符,由后往前
*/
void inverse2(char *str) {
    if (str == NULL) return;

    //到达字符串末尾,结束递归
    if (*str == '\0') return;

    inverse2(str + 1);
    printf("%c", *str);

}
/*
将反转后的字符串保存到全局变量中
*/

//全局变量被修改,多线程操作中会涉及到线程安全的问题
char buf[100];
void inverse3(char *str) {
    if (str == NULL) return;

    //到达字符串末尾,结束递归
    if (*str == '\0') return;

    inverse3(str + 1);
    strncat(buf, str,1);
}
void main() {
    char a[] = "abcdefg";
    //inverse1(a);
    //printf("%s\n", a);
    //inverse2(a);

    memset(buf, 0, sizeof(buf));
    inverse3(a);
    printf("buf = %s\n", buf);
    system("pause");
}
7.const深入理解
int main(){
  const int a;
  int const b;
  const char *c;
  char * const d;
  const char * const e;
}

1.const修饰常量,前两种情况是相同的,表示常量ab都不能被修改
2.const修饰指针,第三种是一个指向常整型的指针,他所指向的内存数据不能被修改,但是他本身可以被修改,也就是所,可以修改他指向的地址
3.const修饰指针,第四种是一个常量指针,指针变量不能被修改,但是他指向的内存空间可以被修改,不能改变指向,但是值可变
4.const修饰指针,第五种是一个指向常整型的常量指针,指针和他指向的内存空间都不能被修改

8.二级指针做函数参数的作用

通过二级指针做参数的好处是,可以用于修改原一级指针所指向的内存,同时也可以修改原一级指针的指向。那么直接用一级指针做参数进行传递就做不到这两点了吗,答案是,可以做到其中以点,就是操作原一级指针指向的内存,但是无法对原一级指针进行操作

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/*
    二级指针做函数参数,用于修改传入一级指针的指向
*/
int getMem(char **a1, int *myLen1, char ** a2, int *myLen2) {
    char *temp1 = NULL;
    char *temp2 = NULL;
    temp1 = (char *)malloc(100);
    if (temp1 == NULL) {
        return -1;
    }
    strcpy(temp1, "hello");

    //让传入的二级指针指向的指针指向temp指向的内存空间
    //这行代码的意思:*a1表示p1,让p1指向了temp1指向的空间
    *a1 = temp1;

    temp2 = (char *)malloc(100);
    if (temp2 == NULL) {
        return -1;
    }
    strcpy(temp2, " world");
    *a2 = temp2;

}
/*
 通过二级指针释放一级指针指向的内存
*/
void freeMem(char** temp1, char **temp2) {
    if (temp1 == NULL || temp2 == NULL)
    {
        return;
    }
    free(*temp1);
    *temp1 = NULL;
    free(*temp2);
    *temp2 = NULL;
}

/*
    如果传入一级指针释放内存会怎样?
*/
void freeMem(char* temp1, char *temp2) {
    if (temp1 == NULL || temp2 == NULL)
    {
        return;
    }
    free(temp1);

    //这一步只是将局部变量temp1设置为null,所以并不影响main函数
    //中p1这个变量,所以传递一级指针,无法操作原一级指针变量
    temp1 = NULL;
    free(temp2);

    //这一步只是将局部变量temp2设置为null,所以并不影响main函数
    //中p2这个变量,所以传递一级指针,无法操作原一级指针变量
    temp2 = NULL;
}
void main() {
    char *p1 = NULL;
    int len1 = 0;
    char *p2 = NULL;
    int len2 = 0;
    int ret;
    ret = getMem(&p1, &len1, &p2, &len2);
    printf("%s\n", p1);
    printf("%s\n", p2);
    freeMem(&p1, &p2);
    system("pause");
}
9.二级指针做输入,指向指针数组
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void printArr(char** temp, int num) {
    int i = 0;
    for (; i < num; i++) {
        //注意,这里*(temp) = *(temp+0) ,二级指针指向
        //指针数组,*(temp+i)表示的是原数组arr中的第i
        //个元素的地址,而我们知道,C语言直接打印数组
        //元素的地址,就会将数组元素打印出来
        printf(" *(temp + %d)  = %s\n", i, *(temp + i));

    }
}

void bubbleSort(char **temp, int num) {

    int i = 0, j = 0;
    for (int i = 0; i<num - 1; i++) {//外层循环控制排序趟数
        for (int j = 0; j<num - 1 - i; j++) {//内层循环控制每一趟排序多少次
            
            if (strcmp(*(temp + j),*(temp + j + 1))>0)
            {
                char *smallest = *(temp + j);
                *(temp + j) = *(temp + j + 1);
                *(temp + j + 1) = smallest;
            }
        }
    }

}

void main() {
    //这是一个指针数组,存放的是是每个元素的地址
    char *arr[] = {"aaaaa","ccccc","ddddd","bbbbb"};
    int num = sizeof(arr) / sizeof(arr[0]);

    printf("数组的长度是:%d\n", num);

    printf("排序之前\n");


    printArr(arr, num);

    bubbleSort(arr, num);
    printf("排序之后\n");
    printArr(arr, num);
    system("pause");
}
二级指针做输入第一种形式.png

顺便复习一下冒泡排序

原理:依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。重复第一趟步骤,直至全部排序完成。

举例说明:要排序数组:int[] arr={6,3,8,2,9,1};

第一趟排序:
    第一次排序:6和3比较,6大于3,交换位置: 3 6 8 2 9 1
    第二次排序:6和8比较,6小于8,不交换位置:3 6 8 2 9 1
    第三次排序:8和2比较,8大于2,交换位置: 3 6 2 8 9 1
    第四次排序:8和9比较,8小于9,不交换位置:3 6 2 8 9 1
    第五次排序:9和1比较:9大于1,交换位置: 3 6 2 8 1 9
    第一趟总共进行了5次比较, 排序结果: 3 6 2 8 1 9


第二趟排序:
    第一次排序:3和6比较,3小于6,不交换位置:3 6 2 8 1 9
    第二次排序:6和2比较,6大于2,交换位置: 3 2 6 8 1 9
    第三次排序:6和8比较,6大于8,不交换位置:3 2 6 8 1 9
    第四次排序:8和1比较,8大于1,交换位置: 3 2 6 1 8 9
    第二趟总共进行了4次比较, 排序结果: 3 2 6 1 8 9


第三趟排序:
    第一次排序:3和2比较,3大于2,交换位置: 2 3 6 1 8 9
    第二次排序:3和6比较,3小于6,不交换位置:2 3 6 1 8 9
    第三次排序:6和1比较,6大于1,交换位置: 2 3 1 6 8 9
    第二趟总共进行了3次比较, 排序结果: 2 3 1 6 8 9


第四趟排序:
    第一次排序:2和3比较,2小于3,不交换位置:2 3 1 6 8 9
    第二次排序:3和1比较,3大于1,交换位置: 2 1 3 6 8 9
    第二趟总共进行了2次比较, 排序结果: 2 1 3 6 8 9


第五趟排序:
    第一次排序:2和1比较,2大于1,交换位置: 1 2 3 6 8 9
    第二趟总共进行了1次比较, 排序结果: 1 2 3 6 8 9


最终结果:1 2 3 6 8 9

由此可见:N个数字要排序完成,总共进行N-1趟排序,每i趟的排序次数为(N-i)次,用双重循环语句,外层控制循环多少趟,内层控制每一趟的循环次数

10.二级指针做输入,第二种形式
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void main() {
    int i = 0;
    char **p2 = NULL;
    int num = 5;

    //在堆空间中开辟内存空间,大小是sizeof(char*)*num,
    //用于存储5个char*类型的指针变量
    p2 = (char **)malloc(sizeof(char*)*num);
    //开辟空间之后给每个元素赋值
    for (i = 0; i < num; i++) {
        //给每个char*类型的指针变量开辟指向的内存空间,这个空间
        //用于存放char类型的数据,最大可存100个char
        *(p2+i) = (char*)malloc(sizeof(char) * 100);

        //赋值
        sprintf(*(p2 + i), "存入我的数据%d,", i + 1);
    }
    for (i = 0; i < num; i++) {
        printf("%s\n", *(p2 + i));
    }


    //释放
    for (i = 0; i < num; i++) {
        if (*(p2 + i) != NULL) {
            free(*(p2 + i));
            *(p2 + i) = NULL;
        }
    }
    if (p2 != NULL)
    {
        free(p2);
        p2 = NULL;
    }
    system("pause");
}
void main2() {
    int i = 0;
    char **p2 = NULL;
    int num = 5;

    //在堆空间中开辟内存空间,大小是sizeof(char*)*num,
    //用于存储5个char*类型的指针变量
    p2 = (char **)malloc(sizeof(char*)*num);
    //开辟空间之后给每个元素赋值
    for (i = 0; i < num; i++) {
        //给每个char*类型的指针变量开辟指向的内存空间,这个空间
        //用于存放char类型的数据,最大可存100个char
        p2[i] = (char*)malloc(sizeof(char) * 100);

        //赋值
        sprintf(p2[i], "存入我的数据%d,", i + 1);
    }
    for (i = 0; i < num; i++) {
        printf("%s\n", p2[i]);
    }


    //释放
    for (i = 0; i < num; i++) {
        if(p2[i] != NULL) {
            free(p2[i]);
            p2[i] = NULL;
        }
    }
    if (p2 != NULL)
    {
        free(p2);
        p2 = NULL;
    }
    system("pause");
}
二级指针第二种形式.png
11.二级指针操作字符串练习

切割字符串并存储在堆内存中,然后打印切割结果
char *p1 = "abcdef,acccd,eeee,aaaa,e3eeeee,sssss,ssccccccc,";

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int splitString(const char *buf1, char c, char** myp, int *count) {
    char *p = NULL, *ptmp = NULL;
    int tmpcount = 0;

    //两个指针都指向了字符串指针
    p = buf1;
    ptmp = buf1;

    do {
        //从p中找char c
        p = strchr(p, c);
        if (p != NULL) {
            //大于0说明指针已经有移动位置,新的字符串和旧的不是同一个,
            //如果字符串第一个字符就找到了符合条件的,那么p-pmt = 0
            if (p - ptmp > 0) {
                //找到一个逗号后,将逗号之前的字符串拷贝到二级指针指向的空间中
                strncpy(*(myp + tmpcount), ptmp, p - ptmp);
                //在截出来的字符串后边添加字符串结束符\0
                *(*(myp + tmpcount) + (p - ptmp)) = '\0';
                tmpcount++;
                ptmp = p = p + 1;
                /*strncpy(myp[tmpcount], ptmp, p - ptmp);
                myp[tmpcount][p - ptmp] = '\0';
                tmpcount++;
                ptmp = p = p + 1;*/
            }
        }
        else {
            break;
        }
    } while (*p != '\0');
    *count = tmpcount;
    return *count;
}
void main() {
    int ret = 0, i = 0;
    char *p1 = "abcdef,acccd,eeee,aaaa,e3eeeee,sssss,ssccccccc,";
    char cTemp = ',';
    int count;

    //开辟空间
    char **p = NULL;
    p = (char **)malloc(10 * sizeof(char *));
    if (p == NULL) {
        return;
    }
    for (i = 0; i < 10; i++) {
        *(p + i) = (char *)malloc(sizeof(char)*30);
        //p[i] = (char *)malloc(sizeof(char) * 30);
    }

    ret = splitString(p1, cTemp, p, &count);

    printf("得到了%d个元素\n", count);
    if (ret == 0)
    {
        printf("error\n");
    }

    for (i = 0; i < count; i++) {
        printf("%s\n", *(p + i));
    }


    //回收内存
    for (i = 0; i < 10; i++) {
        if (*(p + i) != NULL) {
            free(*(p + i));
            *(p + i) = NULL;
        }
    }
    if (p != NULL)
    {
        free(p);
        p = NULL;
    }

    //释放
    /*for (i = 0; i < num; i++) {
        if (p2[i] != NULL) {
            free(p2[i]);
            p2[i] = NULL;
        }
    }
    if (p2 != NULL)
    {
        free(p2);
        p2 = NULL;
    }*/
    system("pause");
}
12.定义数组指针的三种方式

1)通过数组类型定义数组指针
typedef int(ArrayType)[5];
ArrarType *pointer;

  1. 声明一个数组指针类型
    typedef int (*MyPointer)[5];
    MyPointer myPoint;
  2. 直接定义
    int(*pointer)[n];
    ponter为数组指针变量名
    type (int)为指向的数组的类型
    n 为指向的数组的大小
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void main() {
    //直接定义一个指向数组的数组指针变量
    int(*PArrayType)[5];

    //定义一个数组,相当于一级指针
    int myArray2[5];

    //数组指针指向这个数组,相当于二级指针
    PArrayType = &myArray2;
    

    int i = 0;

    for (i = 0; i < 5; i++) {
        (*PArrayType)[i] = i + 1;
    }

    for (i = 0; i < 5; i++) {
        printf("%d", (*PArrayType)[i]);
    }
    system("pause");
}
void main2() {
    char *MyArray[] = {"1111","2222","3333"};
    //数组指针,一个指针,指向了数组

    //定义了一个数组数据类型
    typedef int(MyArrayType)[5];

    int i = 0;

    //用类型定义变量,相当于int myArray[5]
    MyArrayType myArray;

    //定义一个指针变量,这个变量指向数组
    MyArrayType *pArray;

    //定义一个数组,相当于一级指针
    int myArray2[5];

    //数组指针指向这个数组,相当于二级指针
    pArray = &myArray2;

    for (i = 0; i < 5; i++) {
        (*pArray)[i] = i + 1;
    }

    for (i = 0; i < 5; i++) {
        printf("%d", (*pArray)[i]);
    }
    system("pause");
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容

  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,432评论 3 44
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  • 一、框架 1、Mac系统及常用工具、进制;C数据类型、常量变量、运算符、表达式、格式化输入输出 2、关系运算符、逻...
    师景福阅读 685评论 0 1
  • 生活不止眼前的苟且,还有远方的民谣。 南下——徐海俏 慵懒的嗓音入耳,竟分辨不出是男是女,一个听过就不会忘记的声音...
    时光舅舅阅读 451评论 0 0
  • 对于谈恋爱来说,一天一天过得是相当快。然而,我与写作谈恋爱,下场真是难堪。 2016年5月25日,距离柴头第一次写...
    紫柴子阅读 336评论 2 5