如何查询网站建设进度并租用公司电脑?
摘要:网站建设进度报告,公司电脑租用,网站开发软件搭配,兰州网站建设模板无特殊说明情况下,下面所有题s目都是linux下的32位C程序。 「1、计算以下sizeof的值。」 char str1[]{a, b, c
网站建设进度报告,公司电脑租用,网站开发软件搭配,兰州网站建设模板无特殊说明情况下#xff0c;下面所有题s目都是linux下的32位C程序。
「1、计算以下sizeof的值。」
char str1[] {a, b, c, d, e};
char str2[] abcde;char *ptr abcde;char book[][80]{计算机应用基础,C语言,C程…无特殊说明情况下下面所有题s目都是linux下的32位C程序。
「1、计算以下sizeof的值。」
char str1[] {a, b, c, d, e};
char str2[] abcde;char *ptr abcde;char book[][80]{计算机应用基础,C语言,C程序设计,数据结构};sizeof(str1)?
sizeof(str2)?
sizeof(ptr)?
sizeof(book)?
sizeof(book[0])?
「分析」
sizeof(str1)5就是5*sizeof(char)5
sizeof(str2)6字符串都是以\0结尾所以所占字节数为6
sizeof(ptr)4ptr是一个指针在32位平台上大小为4字节
sizeof(book)320book是一个二维数组4801
sizeof(book[0])80book[0]是第一维数组因为此80*1
根据sizeof求数组元素的个数也很简单拿第一个来说就是sizeof(str1)/sizeof(char)。
「2、上面是求计算他们所占字节数下面来看看怎么求字符串或数组的实际长度。计算下面strlen值。」
char arryA[] {a,b,c,\0,d,e};
char arryB[] {a,b,c,d,e};
char arryC[6] {a,b,c,d,e};
char *str abcde;「分析」
strlen(arryA) 3strlen遇到\0就会返回无论后面有多少个字符
strlen(arryB)长度无法确定没有人为写入‘\0’strlen会继续计算直到找到结束符结果未知
strlen(arryC)5指定了数组大小编译器会自动在空余地方添加\0这其实跟char arryC[6] {a,b,c,d,e,\0};等价。
strlen(str) 5不包括结尾的\0。
由以上两个我们来看看strlen和sizeof的区别
1、sizeof是C语言中的一个单目运算操作符类似、--等
用于数据类型sizeof(type)比如sizeof(int)
用于变量sizeof(var_name)
注意sizeof不能用于函数类型、不完全类型或位字段。不完全类型是指具有未知存储大小的数据类型比如未知存储大小的数组类型、
未知内容的结构体或联合类型void类型等。例如sizeof(max)若此时变量max定义为int max(); sizeof(char_v)此时char_v
定义为char char_v[MAX]且MAX未知。
2、strlen是个函数其原型为unsigned int strlen(char *s);
streln的计算必须依赖字符序列中的\0通过该字符来判断字符序列是否结束。
「3、忽悠人的char str[]和char *str」
1下面的操作合法么出错的话会是在那个阶段编译时期还是运行时期
char str[] hello;
str[0] s; //合法么char *str hello;
p[0] s; //合法么「分析」
这两个都可以成功编译只是第二个会在运行时期出现段错误。下面来分析一下
首先hello是一个字符串常量存储在静态数据区域(data段)这是在编译时期就确定的。第一个是将字符串常量赋值给了一个变量全局变量在数据段局部变量在栈区实际上是将字符串常量拷贝到了变量内存中因此修改的只是str[]这个变量的值。
第二个是将字符串常量的首地址赋值给p对p操作就是对字符串常量进行修改因此出现了段错误。
2理解了上面的知识判断一下下面的true or false
char str1[] abc;
char str2[] abc;const char str3[] abc;
const char str4[] abc;const char *str5 abc;
const char *str6 abc;char *str7 abc;
char *str8 abc;cout ( str1 str2 ) endl;
cout ( str3 str4 ) endl;
cout ( str5 str6 ) endl;
cout ( str7 str8 ) endl;「分析」
结果是0 0 1 1
先理解str1,str2,str3,str4他们是什么他们是数组名也就是数组首元素的地址”str1 str2“本质就是比较两个数组的地址是不是相同。上面我们说过编译器给他们分配了新的存储空间来对字符串abc进行拷贝这些变量在内存里是相互独立的因此他们的地址肯定不同
再理解str5,str6,str7,str8他们是什么他们是指针他们的值就是字符串常量的地址它们都指向“abc所在的静态数据区所以他们都相等。
3更深一步下面程序有问题么有的话问题出在哪里如何修改
#include stdio.h
char *returnStr()
{char p[]hello world!;return p;
}
int main()
{char *str NULL;str returnStr();printf(%s\n, str);return 0;
}「分析」
p是个局部变量只是把字符串hello word!进行了拷贝该局部变量是存放在栈中的当函数退出时栈被清空p会被释放因此返回的是一个已经被释放的内存地址这样做是错误的。
可以进行如下修改
#include stdio.h
char *returnStr()
{char *p hello world!;return p;
}
int main()
{char *str NULL;str returnStr();printf(%s\n, str);return 0;
}搜索公众号C语言中文社区后台回复“资源”免费获取200G编程资料。
这么写就不会有问题了因为hello world!存放在静态数据区将该区的首地址赋值给指针p并返回即使returnStr函数退出也不会对字符串常量所在的内存进行回收因此可以访问该字符串常量。
当然了也可以这么修改
#include stdio.h
char *returnStr()
{static char p[] hello world!;return p;
}
int main()
{char *str NULL;str returnStr();printf(%s\n, str);return 0;
}使用关键字staticstatic修饰的局部变量也会放在data段即使returnStr函数退出也不会收回该内存空间。
「4、数组作为函数参数传递」
我们往往会把数组当做函数的入参看看下面的函数有啥问题
int func(int a[]){ int n sizeof(a)/sizeof(int); for(int i0;in;i) { printf(%d ,a[i]); a[i]; }
} 结果却发现n的值总是1为什么会这样呢这是因为在C中将数组传递给一个函数时无法按值传递而是会自动退化为指针。下面的三种写法其实是等价的
int func(int a[20]); 等价于 int func(int a[]); 等价于 int func(int *a);。
「5、两数交换的那些坑」
下面代码想实现两数交换有什么问题么
void swap(int* a, int* b)
{ int *p; p a; a b; b p;
} 「分析」
程序在运行到调用函数时会将参数压栈并为之分配新的空间此时传递进来的其实是一个副本如下图所示 image
a的值跟b的值都是地址交换a和b的值只是把两个地址交换了而已也就说只是改变了副本的地址而已地址所指向的对象并没有改变。
正确的方法应该是这样的
void swap(int* a, int* b)
{ int tmp; tmp *a; *a *b; *b tmp;
} a和b虽然也是副本但是在函数内部通过该地址直接修改了对象的值对应的实参就跟着发生了变化。
其实指针传递和值传递的本质都是值传递值传递是传递了要传递变量的一个副本。复制完后实参的地址和形参的地址没有任何联系对形参地址的修改不会影响到实参但是对形参地址所指向对象的修改却能直接反映在实参中这是因为形参所指向的对象就是实参的对象。正因如此我们在传递指针作为参数时要用const进行修饰就是为了防止形参地址被意外修改。
「6、函数参数为指针应小心」
下面的代码有什么问题运行结果会怎么样
void GetMem(char *p)
{p (char*)malloc(100);
}void main()
{char *str NULL;GetMem(str);strcpy(str, hello word!);printf(str);
}「分析」
程序崩溃。在上面已经分析过了传递给GetMem函数形参的只是一个副本修改形参p的地址对实参str丝毫没有影响。所以str还是那个str仍为NULL这时将字符串常量拷贝到一个空地址必然引发程序崩溃。下面的方法可以解决这个问题
void GetMem(char **p)
{*p (char*)malloc(100);
}void main()
{char *str NULL;GetMem(str);strcpy(str, hello word!);printf(str); free(str); //不free会引起内存泄漏
}看似有点晦涩其实很好理解。本质上是让指针变量str指向新malloc内存的首地址也就是把该首地址赋值给指针变量str。前面我们说过指针传递本质上也是值传递要想在子函数修改str的值必须要传递指向str的指针因此子函数要传递的是str的地址这样通过指针方式修改str的值将malloc的内存首地址赋值给str。
「7、数组指针的疑惑」
1说出下面表达式的含义
int *p1[10];
int (*p2)[10];第一个是指针数组首先他是一个数组数组的元素都是指针。
第二个是数组指针首先他是一个指针它指向一个数组。
下面这张图可以很清楚的说明 image
2写出下面程序运行的结果
int a[5] { 1, 2, 3, 4, 5 };
int *ptr (int *)(a 1);
printf(%d,%d, *(a 1), *(ptr - 1)); 「分析」
答案是2,5。本题的关键是理解指针运算”1“就是偏移量的问题一个类型为T的指针移动是以sizeof(T)为单位移动的。
**a1:**在数组首元素地址的基础上偏移一个sizeof(a[0])单位。因此a1就代表数组第1个元素为2
a1在数组首元素的基础上偏移一个sizeof(a)单位a其实就是一个数组指针类型为int()[5]。因此a1实际上是偏移了5个元素的长度也就是a5再看ptr是int类型因此ptr-1就是减去sizeof(int*)即为a[4]5;
a是数组首地址也就是a[0]的地址a1是数组下一个元素的地址即a[1]a是对象的首地址a1是下一个对象的地址即a[5]。
「8、二级指针疑问」
给定声明 const char * const *pp;下列操作或说明正确的是
App B(*pp) C(**pp)\c\; D以上都不对
「分析」
答案是A。
先从「一级指针」说起吧1const char p 限定变量p为只读。这样如p2这样的赋值操作就是错误的。2const char p p为一个指向char类型的指针const只限定p指向的对象为只读。这样pa或 p等操作都是合法的但如p4这样的操作就错了 因为企图改写这个已经被限定为只读属性的对象。
3char const p 限定此指针为只读这样pa或 p等操作都是不合法的。而p3这样的操作合法因为并没有限定其最终对象为只读。4const char const p 两者皆限定为只读不能改写。再来看「二级指针」问题1const char 「p p为一个指向指针的指针const限定其最终对象为只读显然这最终对象也是为char类型的变量。故像」p3这样的赋值是错误的 而像pp这样的操作合法。
2const char * const *p 限定最终对象和 p指向的指针为只读。这样 *p?的操作也是错的但是p这种是合法的。3const char * const * const p 全部限定为只读都不可以改写
「9、*p、 (*p)、 *p、 *p」
int a[5]{1, 2, 3, 4, 5};
int *p a;*p 先取指针p指向的值数组第一个元素1再将指针p自增1cout *p; // 结果为 1cout (*p); // 1(*p) 先去指针p指向的值数组第一个元素1再将该值自增1数组第一个元素变为2cout (*p); // 1cout ((*p)) // 2
*p 先将指针p自增1此时指向数组第二个元素* 操作再取出该值cout *p; // 2cout (*p) // 2*p 先取指针p指向的值数组第一个元素1再将该值自增1数组第一个元素变为2cout *p; // 2 cout (*p) // 2
