问题1、数组和指针的区别
数组名不可以作为左值
char * p1 = "Hello World" ; //分配字符串常量,然后赋给 p1 ,一个指针型变量,是左值
char p2[ ] = "Hello World" ; //分配一个数组,然后初始化为字符串,相当于一个常量,类型为数组,不是左值 *p1 = 'h' ; //p1可以指向别的地方,但hello world不能更改
p2[ ] = 'h' ; //p2不能指向别的地方,但hello world可以更改
sizeof运算
sizeof(指针变量p1)是编译器分配给指针(也就是一个地址)的内存空间。
sizeof(数组指针常量p2)是整个数组占用空间的大小。但当数组作为函数参数进行传递时,数组就自动退化为同类型的指针。
取地址&运算
对数组名取地址&运算,得到的还是数组第一个元素的地址
对指针取地址&运算,得到的是指针所在的地址,也就是指向这个指针的指针。因此main函数的参数char *argv[],也可以写成char **argv。
参考
问题2、指针数组、数组指针与二维数组剖析
定义
指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身决定。它是“储存指针的数组”的简称。 数组指针:首先它是一个指针,它指向一个数组。在32 位系统下永远是占4 个字节,至于它指向的数组占多少字节,不知道。它是“指向数组的指针”的简称。
实例区分
int *p1[]; //p1 是数组名,其包含10 个指向int 类型数据的指针,即指针数组 int (*p2)[]; //p2 是一个指针,它指向一个包含10 个int 类型数据的数组,即数组指针 cout<<sizeof(a)<<" "<<sizeof(b); //4 40
实例分析
符号优先级: ()> [ ] > *
p1 先与“[]”结合,构成一个数组的定义,数组名为p1,int *修饰的是数组的内容,即数组的每个元素。
“*”号和p2 构成一个指针的定义,指针变量名为p2,int 修饰的是数组的内容,即数组的每个元素。数组在这里并没有名字,是个匿名数组。
数组和指针参数是如何被编译器修改的?
“数组名被改写成一个指针参数”规则并不是递归定义的。数组的数组会被改写成“数组的指针”,而不是“指针的指针”:
实参 所匹配的形参 数组的数组 char c[][]; char (*)[]; 数组指针 指针数组 char *c[]; char **c; 指针的指针 数组指针(行指针) char (*c)[]; char (*c)[]; 不改变 指针的指针 char **c; char **c; 不改变
void f(char **c){
cout<<c[][]<<endl;
} int main(){
char *c[]={"abc","def","ghi"};
f(c);
}
*c[3] 表示这是一个一维数组,数组内的元素是char *类型,每个元素分别指向一个字符串。因为 [] 优先级大于 * 的优先级。
问题3、结构体和数组
数组中存放的是连续的元素,比如int、char等。同样,可以存放struct元素。
实例
struct UnionFieldInfo
{
int flag; //字段选中标识: 0 未选中 1 选中
char *field; // 选中字段
char *fieldDetail; //选中字段在数据库中具体表示
}; struct UnionFieldInfo HACAlarmAudioInfo[] = {
{0, "time", "events.time"},
{0, "matchRule", "events.content"},
{0, "level", "events.rule_level"},
{0, "userName", "session.username"},
{-1, NULL, NULL},
}; /* int flag*/
int UnionGetAlarmFieldInit()
{
int i = 0;
for (i = 0; i < sizeof(HACAlarmAudioInfo)/sizeof(HACAlarmAudioInfo[0]); i++)
{
HACAlarmAudioInfo[i].flag = 0; //init
}
return 0;
} /* get field */
static char * UnionGetAlarmField(char *Field)
{
int i = 0;
for (i = 0; i < sizeof(HACAlarmAudioInfo)/sizeof(HACAlarmAudioInfo[0]); i++)
{
if(HACAlarmAudioInfo[i].flag == 1)
{
return HACAlarmAudioInfo[i].field;
}
}
return NULL;
} /* make fielddetail sql */
int UnionMakeAlarmFieldSQL(char *sql)
{
int i = 0;
for (i = 0; i < sizeof(HACAlarmAudioInfo)/sizeof(HACAlarmAudioInfo[0]); i++)
{
if(HACAlarmAudioInfo[i].flag == 1)
{
sprintf(sql+strlen(sql), "%s, ", HACAlarmAudioInfo[i].fieldDetail);
}
}
/*cancel ", "*/
if(strlen(sql) >= strlen(", "))
{
tinysql[strlen(sql)-strlen(", ")] = 0;
}
}
一维数组HACAlarmAudioInfo中存放的是struct UnionFieldInfo元素。
问题4、带逗号的字符串分隔
使用strtok进行分隔带有逗号的字符串
if (strlen(stApplyInfo.userGroupID))
{
char *tmpstr = NULL;
char s[] = ","; tmpstr = strtok(stApplyInfo.userGroupID, s); //返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。
while(tmpstr)
{
memset(sql, , );
UnionDBPrintf(sql, , "insert into workOrder_userGroup(workOrder, userGroupID) values('%s','%d')", worknote, atoi(tmpstr));
UnionLogDebugEx("draw.log","sql=[%s]",sql);
UnionErr = UnionDBInsert(sql, &row, &errmsg); if (UnionErr)
{
UnionLogErrEx("draw.log", "db insert failed:[%s]", errmsg);
free(sql);
return UnionErr;
}
tmpstr = strtok(NULL, s);
}
}
问题5、字符串拷贝函数
最好使用memcpy()、snprintf()函数进行字符串拷贝。而strcpy()、strncpy()不太好。
strcpy()容易溢出,只用于字符串的拷贝。
strcpy(p+1, p); //内存重叠
char * strcpy(char * dest, const char * src) // 实现src到dest的复制
{
if ((src == NULL) || (dest == NULL)) //判断参数src和dest的有效性
{
return NULL;
} char *strdest = dest; //保存目标字符串的首地址
while ((*strDest++ = *strSrc++)!='\0'); //把src字符串的内容复制到dest下 return strdest;
}
strncpy()标准用法
strncpy(path, src, sizeof(path) - );
path[sizeof(path) - ] = '/0';
len = strlen(path);
memcpy将N个字节的源内存地址的内容拷贝到目标内存地址中。
对于需要复制的内容没有限制,复制任意内容,例如字符数组、整型、结构体、类等。
当源内存和目标内存存在重叠时,memcpy会出现错误。
memcpy(p+1, p, 512); //内存重叠
void* memcpy(void* dest, const void* src, size_t n)
{
assert((NULL != dest) && (NULL != src));
char* d = (char*) dest;
const char* s = (const char*) src; while(n-–)
*d++ = *s++;
return dest;
}
内存重叠
函数strcpy和函数memcpy都没有对内存重叠做处理的,使用这两个函数的时候只有程序员自己保证源地址和目标地址不重叠,或者使用memmove函数进行内存拷贝。
memmove函数对内存重叠做了处理。内存重叠时,使用strcpy函数则程序会崩溃。使用memcpy的话程序会等到错误的结果。
memmove将N个字节的源内存地址的内容拷贝到目标内存地址中
当源内存和目标内存存在重叠时,能正确地实施拷贝,但这也增加了一点点开销。
void* memmove(void* dest, const void* src, size_t n)
{
assert((NULL != dest) && (NULL != src));
char* d = (char*) dest;
const char* s = (const char*) src; if (s>d)
{
// start at beginning of s
while (n--)
*d++ = *s++;
}
else if (s<d)
{
// start at end of s
d = d+n-;
s = s+n-; while (n--)
*d-- = *s--;
}
return dest; //do nothing
}
()内存低端 <-----s-----> <-----d-----> 内存高端 start at end of s
()内存低端 <-----s--<==>--d-----> 内存高端 start at end of s
()内存低端 <-----sd-----> 内存高端 do nothing
()内存低端 <-----d--<==>--s-----> 内存高端 start at beginning of s
()内存低端 <-----d-----> <-----s-----> 内存高端 start at beginning of s
(1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝
(2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝
(3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝
问题6、字符串查找函数
strstr() 函数
char *strstr(const char *haystack, const char *needle) 参数说明:
haystack -- 要被检索的 C 字符串。
needle -- 在 haystack 字符串内要搜索的小字符串。 返回值:
该函数返回在 haystack 中第一次出现 needle 字符串的位置,如果未找到则返回 null。 实例:
ret = strstr("RUNOOB", "NOOB");
printf("子字符串是: %s\n", ret); //"NOOB"
代码实现
#include <cstring>
#include <iostream>
#include <cassert> using namespace std; char* my_strstr(char* str, char* sub)
{
assert(str != NULL);
assert(sub != NULL); int str_len = strlen(str);
int sub_len = strlen(sub); if (str_len < sub_len) /*不用比较,肯定不是*/
{
return NULL;
} if (str_len != && sub_len == ) /*aaaaaaaaaaaaaaaaaa, "" ,比较需要花费时间很多*/
{
cout << "子串为空。。。" << endl; return NULL;
} if (str_len == && sub_len == ) /*都为空可以直接返回*/
{
cout << "原串和子串都为空 !" << endl; return str;
} for (int i = ; i != strlen(str); ++i)
{
int m = , n = i; cout << "原串剩余的长度 : " << strlen(str + i) << endl;
cout << "子串的长度 : " << sub_len << endl; if (strlen(str + i) < sub_len) /*往后找如果原串长度不够了,则肯定不是*/
{
cout << "子串太长啦。。。" << endl; return NULL;
} if (str[n] == sub[m])
{
while (str[n++] == sub[m++])
{
if (sub[m] == '\0')
{
return str + i;
}
}
}
} return NULL;
}
问题7、const用法
const与指针
const放在*左边表示指针指向的是一个常量,放在*后面表示这是一个常量指针。
int a=, b=; const int* p = &a; //p指向的是一个常量,即p的内容为常量
int const* p = &a; //p指向的是一个常量,即p的内容为常量
p = &b; //可以改变p的指向
//*p = 20; //错误:但是不能改变a的内容 int* const p1 = &a; //p1是一个常量指针,表明指针p1是常量不能进行修改,但是p指的内容是可以修改的
*p1 = ; //p指的内容是可以修改的
//p1=&b; //错误:指针p的指向不能修改
const修饰函数参数
const修改函数参数表示参数不可修改,可起到保护的作用。按值传递的参数加上const是没意义的,因为参数传递的时候是拷贝的。按引用传递时加上const保证传出参数的同时对象也不会被更改。
void foo(const int a)
{
// a=10; //错误,函数参数不可改变
}
const修改成员函数
const修改成员表示该函数不能修改任何成员变量的值,同时不能调用任何非const修饰的函数,因为没有const修饰的函数会修改成员变量的值。const修饰函数放在最后面。
#include<iostream> using namespace std; const int a()//返回值为const
{
return ;
} class A
{
public: int temp;
int fun (int x)const//类中成员函数的函数体由const修饰时,不能改变成员变量的值
{
//temp=5;//修改了temp的值,出错
return ;
}
}; int main()
{
//int v=a();//a()只能作为右值,可以赋给int v和const int v
const int v=a();
cout<<v;
A a;
a.fun();
return ;
}
const修饰返回值
一、常量可以赋给常量和变量。
二、指向常量的指针必须必须赋给指向常量的指针,指向变量的指针可以赋给指向变量或常量的指针。
const char* foo()
{
const char a = 'c';
const char* p = &a;
return p;
} char* const foo2()
{
char a = 'c';
char* const p = &a;
return p;
} const char* const foo3()
{
const char a = 'c';
const char* const p = &a;
return p;
} int main()
{
//char* p = foo(); //error,指向常量的指针不能赋给指向变量的指针
const char* p = foo(); //指向常量的指针
const char* const p4 = foo(); //把变量指针赋给常量指针,合法 char* p2 = foo2(); //把常量指针赋给变量指针,合法
char* const p3 = foo2(); //常量指针
const char* p5 = foo2(); //指向变量的指针可以赋给指向常量的指针 const char* const p6 = foo3(); //指向常量的常量指针
const char* p7 = foo3(); //指向常量的变量指针
//char* const p8 = foo3(); //指向变量的常量指针,error
//char* p9 = foo3(); //指向变量的变量指针,error cin.get();
return ;
}
问题8、代理中的echo调试记录
各种代理(ssh等)调试日志,很难获取。可以使用echo命令,通过以下简单几行代码进行调试。
int ret = ;
char log_cmd[] = {}, buff[] = {};
snprintf(buff, , "%s", "test log by system()");
snprintf(log_cmd, , "echo '%s' >> /tmp/log.txt", buff);
ret = system(log_cmd);
问题9、非root帐户下密钥认证脚本生成中的用户主目录获取
Linux 命令行下可通过 echo $HOME进行获取。
//获取当前用户主目录
char *UnionGetRealHomeDir()
{
char *path = getenv("HOME");
return path;
}
参考
C/C++常见问题汇总的更多相关文章
- CentOS安装Oracle数据库详细介绍及常见问题汇总
一.安装前准备 1.软件硬件要求 操作系统:CentOS 6.4(32bit)Oracle数据库版本:Oracle 10g(10201_database_linux32.zip)最小内存:1G(检查命 ...
- SVN集中式版本控制器的安装、使用与常见问题汇总
SVN是Subversion的简称,是一个开放源代码的版本控制系统,它采用了分支管理系统,集中式版本控制器 官方网站:https://www.visualsvn.com/ 下载右边的服务器端,左边的客 ...
- H5项目常见问题汇总及解决方案
H5项目常见问题汇总及解决方案 H5 2015-12-06 10:15:33 发布 您的评价: 4.5 收藏 4收藏 H5项目常见问题及注意事项 Meta基础知识: H5页 ...
- Installshield脚本拷贝文件常见问题汇总
原文:Installshield脚本拷贝文件常见问题汇总 很多朋友经常来问:为什么我用CopyFile/XCopyFile函数拷贝文件无效?引起这种情况的原因有很多,今天略微总结了一下,欢迎各位朋友跟 ...
- MVC 网站部署常见问题汇总
一:TGIShare项目是一个MVC5的网站程序,部署在了IIS上,使用的Windows验证方式,并在本机设置了计划任务定时调用某个地址执行命令.问题汇总如下: 1.Window Server 200 ...
- J2EE进阶(十)SSH框架整合常见问题汇总(一)
SSH框架整合常见问题汇总(一) 前言 以下所列问题具有针对性,但是遇到同类型问题时均可按照此思路进行解决. HTTP Status 404 - No result defined for actio ...
- mysql进阶(十六)常见问题汇总
mysql进阶(十六)常见问题汇总 MySQL视图学习: http://www.itokit.com/2011/0908/67848.html 执行删除操作时,出现如下错误提示: 出现以上问题的原因是 ...
- 转---CentOS安装Oracle数据库详细介绍及常见问题汇总
一.安装前准备 1.软件硬件要求 操作系统:CentOS 6.4(32bit)Oracle数据库版本:Oracle 10g(10201_database_linux32.zip)最小内存:1G(检查命 ...
- (转)CloudStack 安装及使用过程中常见问题汇总
CloudStack 安装及使用过程中常见问题汇总 在做工程项目中对CloudStack 安装及使用过程中常见的几个问题及如何解决做一个总结. 1.Windows XP虚拟 ...
- thymeleaf的常见问题汇总
thymeleaf的常见问题汇总 1.thymeleaf th:href 多个参数传递格式 th:href="@{/Controller/update(param1=1,param2=${p ...
随机推荐
- 【JVM学习笔记】系统类加载器
可以通过“java.system.class.loader"属性指定系统类加载器 默认情况下,该属性值为空: public class Test { public static void m ...
- 后缀数组--summer-work之我连模板题都做不起
这章要比上章的AC自动机要难理解. 这里首先要理解基数排序:基数排序与桶排序,计数排序[详解] 下面通过这个积累信心:五分钟搞懂后缀数组!后缀数组解析以及应用(附详解代码) 下面认真研读下这篇: [转 ...
- Android 单元测试学习计划
网上查了一下Android单元测试相关的知识点,总结了一个学习步骤: 1. 什么是单元测试2. 单元测试正反面: 2.1. 重要性 2.2. 缺陷 2.3. 策略3. 单元测试的基础知识: 3.1. ...
- 【问题案例】K8S-Master修改IP地址之后,重新初始化的方法。
使用kubeadm命令,执行:kubeadm reset 重新执行初始化:kubeadm init --kubernetes-version=v1.14.1 --pod-network-cidr=10 ...
- web赛题3
2019--21省赛 wp:https://xz.aliyun.com/t/6458 2019-11-22蚂蚁金服(南邮)wp有了,微信 https://platform.d3ctf.io/#/ @d ...
- octotree — 树形展示 Github 项目代码
前言.... octotree 是一款chrome插件,用于将 Github 项目代码以树形格式展示,而且在展示的列表中,我们可以下载指定的文件,而不需要下载整个项目 源码地址: https://gi ...
- J-流浪西邮之寻找火石碎片 【经典背包变形】
题目来源:2019 ACM ICPC Xi'an University of Posts & Telecommunications School Contest 链接:https://www. ...
- springBoot整合Listener
新建项目 这个是pom文件 <properties> <java.version>1.8</java.version> </properties> &l ...
- [转帖]intel发布会之前,漫谈CPU核心架构:CCX、Ring Bus、Mesh
intel发布会之前,漫谈CPU核心架构:CCX.Ring Bus.Mesh https://baijiahao.baidu.com/s?id=1607585351741429318&wfr= ...
- 【Python】【demo实验24】【练习实例】【打印图样】
原题: 打印出如下图案(菱形): * *** ***** ******* ***** *** * 我的源码: #!/usr/bin/python # encoding=utf-8 # -*- codi ...