在C中,可以在声明中使用字符串文字,如下所示:
char s[] = "hello";
Run Code Online (Sandbox Code Playgroud)
或者像这样:
char *s = "hello";
Run Code Online (Sandbox Code Playgroud)
那么区别是什么呢?我想知道在编译和运行时的存储持续时间实际发生了什么.
以下代码在第2行接收seg错误:
char *str = "string";
str[0] = 'z'; // could be also written as *str = 'z'
printf("%s\n", str);
Run Code Online (Sandbox Code Playgroud)
虽然这非常有效:
char str[] = "string";
str[0] = 'z';
printf("%s\n", str);
Run Code Online (Sandbox Code Playgroud)
经过MSVC和GCC测试.
我试图理解C中的指针,但我目前对以下内容感到困惑:
char *p = "hello"
Run Code Online (Sandbox Code Playgroud)
这是一个指向字符数组的char指针,从h开始.
char p[] = "hello"
Run Code Online (Sandbox Code Playgroud)
这是一个存储hello的数组.
将这两个变量都传递给这个函数有什么区别?
void printSomething(char *p)
{
printf("p: %s",p);
}
Run Code Online (Sandbox Code Playgroud) 这个问题在那里向C大师们提出:
在C中,可以如下声明指针:
char (* p)[10];
Run Code Online (Sandbox Code Playgroud)
..这基本上表明这个指针指向一个10个字符的数组.声明这样的指针的巧妙之处在于,如果尝试将不同大小的数组指针分配给p,则会出现编译时错误.如果您尝试将简单char指针的值赋给p,它也会给出编译时错误.我用gcc尝试了这个,它似乎适用于ANSI,C89和C99.
在我看来,声明像这样的指针非常有用 - 特别是在将指针传递给函数时.通常,人们会编写这样一个函数的原型:
void foo(char * p, int plen);
Run Code Online (Sandbox Code Playgroud)
如果您期望具有特定大小的缓冲区,则只需测试plen的值.但是,您无法保证将p传递给您的人真的会在该缓冲区中为您提供有效的内存位置.你必须相信调用这个函数的人正在做正确的事情.另一方面:
void foo(char (*p)[10]);
Run Code Online (Sandbox Code Playgroud)
..会强制调用者为您提供指定大小的缓冲区.
这似乎非常有用,但我从未见过在我遇到过的任何代码中都声明了这样的指针.
我的问题是:人们有没有理由不宣布像这样的指针?我没有看到一些明显的陷阱吗?
C中字符串文字的类型是什么?是char *或const char *否const char * const?
那么C++呢?
我的理解是数组只是指向一系列值的常量指针,当你在C中声明一个数组时,你就是声明一个指针并为它所指向的序列分配空间.
但这让我感到困惑:以下代码:
char y[20];
char *z = y;
printf("y size is %lu\n", sizeof(y));
printf("y is %p\n", y);
printf("z size is %lu\n", sizeof(z));
printf("z is %p\n", z);
Run Code Online (Sandbox Code Playgroud)
使用Apple GCC编译时会得到以下结果:
y size is 20
y is 0x7fff5fbff930
z size is 8
z is 0x7fff5fbff930
Run Code Online (Sandbox Code Playgroud)
(我的机器是64位,指针长8个字节).
如果'y'是常量指针,为什么它的大小为20,就像它指向的值序列一样?变量名'y'是否在编译时被内存地址替换为适当的?那么数组是C中的某种语法糖,它在编译时只是转换为指针的东西吗?
在C语言中调用函数时,我有一些关于默认参数提升的问题.这里是6.5.2.2节"函数调用" C99标准(pdf)中的第6,7和8段(强调添加并分为列表以便于读):
第6段
- 如果表示被调用函数的表达式具有不包含原型的类型,则对每个参数执行整数提升,并将具有类型的参数
float提升为double.这些被称为默认参数促销.- 如果参数数量不等于参数数量,则行为未定义.
- 如果使用包含原型的类型定义函数,并且原型以省略号(
, ...)结尾或者促销后的参数类型与参数类型不兼容,则行为未定义.- 如果使用不包含原型的类型定义函数,并且促销后的参数类型与促销后的参数类型不兼容,则行为未定义,但以下情况除外:
- 一个提升类型是有符号整数类型,另一个提升类型是相应的无符号整数类型,并且该值可在两种类型中表示;
- 这两种类型都是指向字符类型的限定或非限定版本的指针
void.
第7段
- 如果表示被调用函数的表达式具有包含原型的类型,则将参数隐式转换为相应参数的类型,就像通过赋值一样,将每个参数的类型作为其声明的非限定版本类型.
- 函数原型声明符中的省略号表示法导致参数类型转换在最后声明的参数之后停止.默认参数提升是在尾随参数上执行的.
第8段
- 没有其他转换是隐式执行的; 特别是,参数的数量和类型不会与函数定义中不包含函数原型声明符的参数的数量和类型进行比较.
char和short对int/ unsigned int和float到doubleprintf)的可选参数受默认参数提升的约束为了记录,我对函数原型的理解是这样的:
void func(int a, char b, float c); // Function prototype
void func(int a, char b, float c) …Run Code Online (Sandbox Code Playgroud) 在编写一个简单的函数来从字符串中删除特定字符时,我遇到了这个奇怪的问题:
void str_remove_chars( char *str, char to_remove)
{
if(str && to_remove)
{
char *ptr = str;
char *cur = str;
while(*ptr != '\0')
{
if(*ptr != to_remove)
{
if(ptr != cur)
{
cur[0] = ptr[0];
}
cur++;
}
ptr++;
}
cur[0] = '\0';
}
}
int main()
{
setbuf(stdout, NULL);
{
char test[] = "string test"; // stack allocation?
printf("Test: %s\n", test);
str_remove_chars(test, ' '); // works
printf("After: %s\n",test);
}
{
char *test = "string test"; // non-writable?
printf("Test: %s\n", …Run Code Online (Sandbox Code Playgroud) 我该怎么理解char * ch="123"?
'1'是一个char,所以我可以使用:
char x = '1';
char *pt = &x;
Run Code Online (Sandbox Code Playgroud)
但我怎么理解char *pt="123"?为什么能char *pt指向字符串?
是pt的价值为第一地址值"123"?如果是这样,我如何得到指向的字符串的长度pt?
char *p = "some string"
Run Code Online (Sandbox Code Playgroud)
创建指向包含该字符串的块的指针p.
char p[] = "some string"
Run Code Online (Sandbox Code Playgroud)
创建一个字符数组并在其中包含文字.
第一个是常量声明.二维数组是否相同?
有什么区别
char **p,char *p[],char p[][].
Run Code Online (Sandbox Code Playgroud)
我读了一下这个,char**p创建了一个指针数组,因此与char p[][]存储指针值相比,它有一个开销.
前两个声明创建常量arrays.i当我试图修改argvin 的内容时没有得到任何运行时错误main(int argc,char **argv).是因为它们是在函数原型中声明的吗?