0xFFF...FF | 内核区 |
---|---|
栈空间?? | |
( not used ) | |
堆空间?? | |
数据段 | |
代码段 | |
0x000..00 | ( null ) |
int main(){
int arr[N];
func(arr);
}
- 首先进入主调函数
main()
;main()
调用func()
,申请栈帧;- 数组在函数间传递的时候,会退化成传递首地址;
#include <stdio.h> #define SIZE 5 void print(int arr[]){ //void print(int arr[], int length) printf("print, sizeof(arr) = %d\n", sizeof(arr)); for(int i=0; i<SIZE; ++i){ // i < length printf("%3d", arr[i]); } printf("\n"); } int main(){ int arr[SIZE] = {1, 2, 3, 4, 5}; printf("main, sizeof(arr) = %d\n", sizeof(arr)); printf(arr); //print(arr, sizeof(arr)/sizeof(int)); }
在数组传递的时候,必须补充一个额外的 int 参数,用来表示长度 ( 规范代码见注释 );
int arr[2][3];
方括号运算符的结合性是由左到右,即第一个方括号决定了这个数组是几维数组,所以这是一个大小为 2 的 int 型数组,数组的元素是大小为 3 的 int 型数组;从这个角度看,二维数组的本质就是一个一维数组;一维数组的每一个元素都是另一个一维数组,每个元素称为一行,即按行存储;
int arr[2][3] = { {1, 2, 3} , {4, 5, 6} };
//大花括号表示是一个有两个元素的一维数组;
//每个元素又是一个有三个元素的一维数组;
arr[i]
的地址:addr + i*sizeof(int)*4
;
arr[i][j]
的地址:addr + i*sizeof(int)*4 + j*sizeof(int)
;
所以二维数组的列大小是有用的,而行大小缺失,不影响元素的访问;
拓展到多维的情况,那就是只有第一个元素没有用,其他的都是有用的;
二维数组的本质还是一个一维数组,所以在函数调用的时候,传递二维数组还是会退化为一个地址;
#include <stdio.h>
void print(int b[3][4], int length){
//b[3][4]中,行信息没用,可以忽略,而列信息必要
//int b[][4]
printf("sizeof(b) = %d\n", sizeof(b));
for(int i=0; i<length; ++i){
for(int j=0; j<sizeof(b[0])/sizeof(int); ++j){
printf("3d", b[i][j]);
}
}
printf("\n");
}
int main(){
int b[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
print(b, sizeof(b)/sizeof(b[0]));
//length = 数组大小 / 元素大小
}
以‘\o‘
结尾的字符数组被称为字符串,所以字符串要多申请一个空间;
#include <stdio.h>
void myprint(char str[], int length){
for(int i=0; i<length; i++){
if(str[i]==‘\0‘){
return;
}
printf("%c", str[i]);
}
}
/*
void myprint(char str[]){
for(int i=0; str[i]; ++i){
printf("%c", str[i]);
}
printf("\n");
}
*/
int main(){
char str[] = "Hello,world";
printf("%s\n", str);
myprint(str, sizeof(str)/sizeof(char));
//myprint(str);
return 0;
}
Scanf控制字符:
如果用 %s
读取字符串的话,在字符串中间包含空格的话,就会停止读取;
??内存越界问题:如果申请的空间小于访问空间,就会越界写入;( scanf() 对长度没有检查)
char str[5] = { 0 }; scanf("%s", str); //输入 10 个字符的话,会写入到数组以外;
用数组的时候,如果不包含长度信息,就不安全;
char *fgets( char *str, int num, FILE *stream)
,文件指针用:stdin;
fgets(str, 128, stdin); //一次最多取出 n-1 个字符
myprint(str); //可以包含空格
fgets() 读取的时候会读取输入流中的换行符号\n(oA)
。
为了去除这个换行符号的影响,可以算出其位置,一般是最后一个位置,借助size_t strlen(char *str)
,可以返回到控制符号(‘\0‘)之前有多长;
if(‘\n‘ == str2[strlen(str2) - 1]){
str2[strlen(str2) - 1] = ‘\0‘;
}
char *strcpy(char *to, const char *from)
在遇到 from 的终止符之前,把from中的字符写入到 to 中;由于没有检查数组的长度,因此也是一种不安全的方法;
int strcmp(const char *str1, const char *str2);
比较大小的时候,使用字典序:
return | meaning |
---|---|
< 0 | Str1 < str2 |
= 0 | equal |
> 0 | str1 > str2 |
char *strcat( char *str1, const char *str2);
是一个不安全的函数,不检查字符串的长度;函数找到第一个字符串的终止符,然后从此开始写入,然后把最后一个位置添加一个终止符,最后返回首地址;
void *memcpy(void *to, const void *from, size_t count);
函数从 from 中复制 count 个字符到 to 中,并返回 to 指针,如果 to 和 from 重叠,则函数行为不确定;
void *memset(void *buffer, int ch, size_t count)
拷贝 ch 到 buffer 从头开始的 count 个字符中,并返回 buffer 指针,在运行的时候,int ch
会进行一次类型转换;
原文:https://www.cnblogs.com/CharminZh/p/15048402.html