[英]get and set values of a char array via pointer arithmetic in c
我在c中缺少有关指针和字符串的东西。 我试图简单地获取并设置通过指针创建的c中的字符数组的元素。 我可以通过指针算法轻松获得每个字符,但无法通过指针算法设置任何元素。 请参见示例。 我在这里想念什么? 两个示例中的s1不一样吗? 我在win10上使用mingw(gcc)。
例子A)这有效,s1被打印为“ abxd”
char *s1;
s1 = (char[]){'a','b','c','d','\0'};
*(s1+2)='x';
printf("%s",s1);
例B)这行不通,只是崩溃。
char *s1;
s1 = "abcd";
*(s1+2)='x'; //this is the problem, can get but can not set
printf("%s",s1);
编辑:基于收到的有关示例B的使用静态内存的评论,无法进行编辑。 所以基本上这意味着如果我要编辑字符串,我必须使用malloc(堆内存,例如C)或在堆栈存储器上定义数组(例如D),对吗?
示例C)-作品
char *s1;
s1 = (char*)malloc((4+1)*sizeof(char));
s1 = strcpy(s1,"abcd");
*(s1+2)='x'; //or s1[2] = 'x'
printf("%s",s1);
例D)-作品
char s1[4]; // would have thought need to be min of s1[5]
s1 = strcpy(s1,"abcd");
*(s1+2)='x'; // or s1[2]='x';
printf("%s",s1);
让我们看看您的示例,并确保您知道发生了什么事。 但是首先,快速回顾一下指针以确保我们在同一页面上:
指针和指针算法
指针只是一个普通变量,将其他地址作为其值。 换句话说,一个指针指向可以找到其他内容的地址。 通常您会想到一个包含立即数的变量,例如int a = 5;
,指针将仅保存内存中存储5
的地址,例如int *b = &a;
。 无论指针指向哪种对象,其工作方式都相同。 之所以能够这样工作,是因为指针的type
控制着指针的算术,例如,使用char *
指针, pointer+1
指向下一个字节,对于int *
指针(普通4字节整数), pointer+1
将指向pointer
之后4字节的偏移量。 (因此,一个指针只是一个指针。...其中算术由type
自动处理)
我在示例A中做什么?
您的初始化是示例A起作用以及示例B崩溃的关键。 示例A使用复合文字来初始化s1
因此s1
指向可修改内存中"abcd"
中的第一个字符'a'
。 复合字词是在C99中引入的,但是gcc也将复合字词作为对C89的扩展。 在示例A中,使用:
s1 = (char[]){'a','b','c','d','\0'};
相当于
s1 = (char[]){ "abcd" };
复合文字是(type){ ..initializer.. }
,关键部分是(type)
,它用作初始值设定为该类型的转换。 在您的示例中,将"abcd"
强制转换为char[]
(字符数组),您可以自由对其进行修改。
为什么示例B崩溃?
另一方面:
s1 = "abcd";
将s1
初始化为string-literal 。 大多数操作系统(通常在可执行文件的.rodata
部分中)在只读存储器中创建一个字符串字面量。 请参阅: 为什么C字符串文字是只读的? 历史的观点。 您无法修改只读内存中的值,并且尝试这样做通常会导致SEGFAULT
(您可能已经发现)。
您对示例D的评论是正确的!
char s1[4];
创建一个带有4个字符(ASCII)的空格的字符数组。 当您调用strcpy (s1, "abcd");
您正在尝试复制多于1个适合的字符:
'a','b','c','d','\0'
1 2 3 4 5
这将导致未定义的行为,并可能导致可利用的缓冲区溢出。 从man 3 strcpy
,
如果strcpy()的目标字符串不够大,则可能会发生任何事情。 固定长度的字符串缓冲区溢出是用于完全控制机器的最受欢迎的破解技术。 每当程序读取数据或将数据复制到缓冲区中时,程序首先需要检查是否有足够的空间。 如果您可以证明不可能发生溢出,则这可能是不必要的,但请注意:程序可能会随着时间的流逝而改变,以可能的方式实现。
因此,就像在示例C中分配了(4+1)
个字符/字节一样,在示例D中的s1
中至少需要存储(4+1)
字符/字节。
记住 ,每个C-library str...
函数都需要一个以nul结尾的字符串。 创建字符数组时,您有责任确保它以nul终止 ,使其成为C中的字符串。如果它不是nul终止 ,则它只是一个字符数组- 每次失败要将以nul结尾的字符串传递给期望一个字符串的函数,该函数将不知道何时停止读取,并且会很高兴地误读越界,直到碰巧遇到零字节或SEGFAULTS(以先发生者为准) 。
仔细检查并消化它们,如果您还有其他问题,请告诉我。 (并在您的printf
格式字符串中添加'\\n'
(例如"%s\\n"
),以便输出换行符-至少在您上次调用时才使程序符合POSIX要求)
第一个示例在读/写存储器中创建char数组,您可以对其进行修改。 第二个是指向只读char数组的指针。 当您尝试修改只读内存位置时,会出现错误。
您还可以通过char x [] =“ 1234”;在读/写存储器中创建数组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.