C语言C语言程序员

C语言数组与指针一本道来

2017-12-04  本文已影响84人  PcDack
数组与指针.png

一本道来其他系列
C语言关键字
C语言注释符号一本道来
C语言编译预处理技术一本道来

指针的基础

注意本节内容可能在gcc下不能完成编译,请切换到Windows平台,使用dev-cpp或其他

*号的意义

最佳实践(指针占用的内存空间)

#include <stdio.h>

int main()
{
    int i;
    int* pI;
    char* pC;
    float* pF;
    
    pI = &i;
    
    printf("%0X, %0X, %d\n", pI, &i, i);
    printf("%d, %d, %0X\n", sizeof(int*), sizeof(pI), &pI);
    printf("%d, %d, %0X\n", sizeof(char*), sizeof(pC), &pC);
    printf("%d, %d, %0X\n", sizeof(float*), sizeof(pF), &pF);
    
    return 0;
}

最佳示例(写地址)需要在VS或其他windows系统下测试,

#include<stdio.h>
int main()
{
    int i;
    int * p;
    p=&i;
    *((int*)0x28FEB8)=100;          
    printf("%0X\n",p);
    printf("%d\n",i);
    return 0;
 } 

传值调用与传址调用

数组的基础

例子

a[5]={1,2}

其中其他的都用0来填充,所以数组最后为

a[5]={1,2,0,0,0}

数组地址与数组名

数组名的盲点

最佳错误

新建一个.c文件

char * p="hello world";

再建一个.c文件

#include<stdio.h>
extern char p[];
void main()
{
    printf("%s\n",p);
}

思路很简单,就是输出hello world,然而输出的结果是错误的,原因就是上面列出来的几点中的一点。
修改

Linux


#include<stdio.h>
extern char p[];
void main()
{
        printf("%s\n",(char *)*(unsigned int *)p);
}

Windows平台


#include<stdio.h>
extern char p[];
void main()
{
        printf("%s\n",(char *)*(unsigned int *)p);
}

虽然会有warning但是程序运行是正确的

C语言中的字符串

char* s1="Hello World1";(在只读存储区)

字符串的长度

标准库,用来解决字符长度

strlen()

彩蛋(一行程序实现strlen)

int strlen(const char * p)
{
    return (assert(s),(* p? strlen(p+1)+1:0));
 
}

不受限制的字符串函数

注意事项

彩蛋(实现strcpy)

char* strcpy(char* dst,const char* src)
{
    char* ret=dst;
    assert(dst && src);
    while((*dst++=*src++)!='\0');//指针循环效率高
    return ret;
}

长度受限制的字符串函数


指针数组和数组指针分析

数组类型

定义数组类型

数组指针

最佳示例

#include <stdio.h>

typedef int(AINT5)[5];
typedef float(AFLOAT10)[10];
typedef char(ACHAR9)[9];

int main()
{
    AINT5 a1;
    float fArray[10];
    AFLOAT10* pf = &fArray;
    ACHAR9 cArray;
    char(*pc)[9] = &cArray;
    char(*pcw)[4] = cArray;
    
    int i = 0;
    
    printf("%d, %d\n", sizeof(AINT5), sizeof(a1));
    
    for(i=0; i<10; i++)
    {
        (*pf)[i] = i;
    }
    
    for(i=0; i<10; i++)
    {
        printf("%f\n", fArray[i]);
    }
    
    printf("%0X, %0X, %0X\n", &cArray, pc+1, pcw+1);
    
    //pc+1指向整个数组的后一个数组
}

指针数组

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

int lookup_keyword(const char* key, const char* table[], const int size)//第二个是指针数组
{
    int ret = -1;
    
    int i = 0;
    
    for(i=0; i<size; i++)
    {
        if( strcmp(key, table[i]) == 0 )
        {
            ret = i;
            break;
        }
    }
    
    return ret;
}

#define DIM(a) (sizeof(a)/sizeof(*a))

int main()
{//指针数组
    const char* keyword[] = {
            "do",
            "for",
            "if",
            "register",
            "return",
            "switch",
            "while",
            "case",
            "static"
    };
    
    printf("%d\n", lookup_keyword("return", keyword, DIM(keyword)));
    printf("%d\n", lookup_keyword("main", keyword, DIM(keyword)));
}

main函数的参数

main函数的四种参数类型

int main()
int main(int argc)
int main(int argc,char *argv[])
int main(int argc,char *argv[],char *env[])

小结


多维数组和多维指针

int main()
{
    int a=0;
    int* p=NULL;
    int** pp=NULL;
    pp=&p;
    *pp=&a;
    return 0;
}

指向指针的指针

最佳示例(动态内存大小更变)

#include<stdio.h>
#include<malloc.h>
int rest(char** p,int size,int new_size)
{
    int ret=1;
    int len=0;
    int i=0;
    char* mid=NULL;
    char* pt=NULL;
    char* pp=*p;
    if((p!=NULL)&&(new_size>0))
    {
        mid=(char*)malloc(3);
        pt=mid;
        len=(size<new_size)?size:new_size;
        for(i=0;i<len;i++)
        {
            *pt++=*pp++;
        }
        free(*p);
        *p=pt;
        
    }else{
        ret=0;
    }
    return ret;
}
void main()
{
    char *p=(char*)malloc(5);
    printf("%0X\n",p);
    if(rest(&p,5,3))
    {
        printf("%0X\n",p);
    }
}

二维数组与数组指针

二维数组.png
#include<stdio.h>
#include<malloc.h>
 void printArray(int a[],int size)
 {
    int i=0;
    printf("printfArray:%d\n",sizeof(a));
    for(i=0;i<size;i++)
    {
        printf("%d\n",a[i]);
     }
 }
 int main()
 {
    int a[3][3]={{0,1,2},{3,4,5},{6,7,8}};
    int *p=&a[0][0];
    printArray(p,9);
    return 0;
    
 }

数组名

#include<stdio.h>
int main()
{
    int a[5][5];
    int (*p) [4];
    p=a;
    printf("%d\n",&p[4][2]-&a[4][2]);
}

答案为-4,因为(*p)一次跨越4个,而a一次跨越5个

数组的遍历

int a[3][3]={{}};
for(i=0;i<3;i++)
for(j=0;j<3;j++)
*(*(a+i)+j)

动态分配二维数组

原理大家很聪明就不解释 二维数组动态分配.png
#include<stdio.h>
#include<malloc.h>
int** malloc2d(int row,int col)
{
    int** ret=(int**)malloc(sizeof(int*)*row);   
    int* p=(int*)malloc(sizeof(int)*row*col);
    int i=0;
    if(ret&&p)
    {
        for(i=0;i<row;i++)
        {
            ret[i]=p+col*i;
        }
    }else{
        free(ret);
        free(p);
        ret=NULL;
        p=NULL;

    }
    return ret;
}
void del_Array(int** a)
{
    free(a);
}
void main()
{
    int i=0,j=0;
    int row=0,col=0;
    printf("please input the row\n");
    scanf("%d",&row);
    printf("please input the col\n");
    scanf("%d",&col);   
    int** p=malloc2d(row,col);
    for(i=0;i<row;i++)
    {
        for(j=0;j<col;j++)
        {
            p[i][j]=i+j;
        }
    }
    for(i=0;i<row;i++)
    {
        for(j=0;j<col;j++)
        {
            printf("%d ",p[i][j]);
        }
        printf("\n");     
    }

}

数组参数和指针参数分析

注意C语言的编译器会让(不论是一维数组还是二维数组)数组参数退化为指针

为什么退化

二维数组参数

void f(int a[10])->void f(int a[])->void f(int *a)
void g(int a[3][3])->void g(int a[][3])->void g(int (*a)[3])

注意事项

#include<stdio.h>
#include<malloc.h>
void access(int a[][3],int row)
{
    int col=sizeof(*a)/sizeof(int);//去推导出列的数量
    int i=0,j=0;
    for(i=0;i<row;i++)
    {
        for(j=0;j<col;j++)
        {
            printf("%d ",a[i][j]);
        }
        printf("\n");
    }
    
}
void main()
{
    int a[3][3]={
    {1,2,3},
    {4,5,6},
    {7,8,9}
    };
    access(a,3);
}

函数与指针分析

函数

函数类型

函数指针

函数指针的本质与使用

回调函数

最佳示例C语言回调函数

#include <stdio.h>

typedef int(FUNC)(int);

int test(int i)
{
    return i * i;
}

void f()
{
    printf("Call f()...\n");
}

int main()
{
    FUNC* pt = test;
    
    //void(*pf)() = &f;//老方法
    
    //pf();
    //(*pf)();//老方法
    
    printf("Function pointer call: %d\n", pt(2));
}

进阶回调

#include <stdio.h>

typedef int(*FUNCTION)(int);

int g(int n, FUNCTION f)
{
    int i = 0;
    int ret = 0;
    
    for(i=1; i<=n; i++)
    {
        ret += i*f(i);
    }
    
    return ret;
}

int f1(int x)
{
    return x + 1;
}

int f2(int x)
{
    return 2*x - 1;
}

int f3(int x)
{
    return -x;
}

int main()
{
    printf("x * f1(x): %d\n", g(3, f1));//注册
    printf("x * f2(x): %d\n", g(3, f2));
    printf("x * f3(x): %d\n", g(3, f3));
}

上一篇 下一篇

猜你喜欢

热点阅读