我正在尝试在Linux(Ubuntu 18.04)的C语言中将char
数组的元素向右移,并尝试为此提供功能。我基本上想将x
个元素添加到数组的开头,并将其余数据移动x
(向右)。如果新元素+旧有效元素超过char
大小,我希望函数返回错误并且不进行任何移位。我还制作了一个指向char
数组的char
指针,并使用结构设置了char
数据。
这是我作为测试程序编写的程序:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
struct struct1
{
char str[10];
int myNum;
};
struct struct2
{
char str[5];
};
int shiftChar(char *arr, int size, int length)
{
for (int i = 0; i < length; i++)
{
// I know I am calculating this incorrectly. Though, not sure how I should go about checking if the new size will exceed the length of the char array.
if (length < ((i + 1) + size))
{
return -1;
}
// If element is 0, we shouldn't shift it (usually represents garbage value?). Not sure how to detect whether an element of a char array was filled with actual data or not.
if (arr[i] == 0)
{
continue;
}
arr[i + size] = arr[i];
fprintf(stdout, "Replacing %c with %c at %d => %d\n\n", arr[i + size], arr[i], i, i + size);
}
for (int i = 0; i < size; i++)
{
arr[i] = 0;
}
return 0;
}
int main()
{
char buffer[256];
struct struct1 *struct1 = (struct struct1 *) (buffer);
struct struct2 *struct2 = (struct struct2 *) (buffer + sizeof(struct struct1));
struct1->myNum = 5;
strncpy(struct1->str, "Hello!", 6);
strncpy(struct2->str, "TST", 3);
fprintf(stdout, "Buffer => ");
for (int i = 0; i < (sizeof (struct struct1) + sizeof(struct struct2)); i++)
{
fprintf(stdout, "%c", buffer[i]);
}
fprintf(stdout, "\n\n");
if (shiftChar(buffer, 6, 256) != 0)
{
fprintf(stdout, "Error shifting char array.\n");
//exit(1);
}
struct1 = (struct struct1 *) (buffer + 6);
struct2 = (struct struct2 *) (buffer + sizeof(struct struct1) + 6);
fprintf(stdout, "struct1->str => %s\n", struct1->str);
exit(0);
}
这是示例输出:
...
Error shifting char array.
struct1->str => Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hell`����
我知道我做错了,但是我不确定我做错了什么,或者我是否应该对此做不同的处理。
我的主要问题是:
shiftChar()
函数我在做什么错?
是否有更好/更轻松的方法来实现我正在尝试的目标?
是否可以检查char
数组中的元素是否具有垃圾值(例如,尚未填写的值)?我想我可以使用0
之类的东西将缓冲区设置为所有memset()
,但是如果我有一个int
指向值为'0'的缓冲区数据的结构,会发生什么。我想如果我检查该值是否等于“ 0”,那么该偏移将被排除在外。
我也对此进行了研究,但是我遇到的大多数线程都是C ++或将元素向左移动。我无法为我的问题找到可靠的解决方案。我将在另一个正在使用的程序中使用该解决方案(如果有),我将需要在开始时将struct iphdr
的大小添加到现有的缓冲区char中(数据已经通过struct iphdr
和[ C0]),这样我就可以创建和发送IPIP数据包(网络编程)。我也知道我可以制作一个全新的char并仅从旧缓冲区复制数据(同时使第一个struct udphdr
元素保持空闲),但是我想这对我的情况会造成很大的性能影响,因为将不得不每秒执行数千次此操作,最好只修改现有缓冲区sizeof(struct iphdr)
。
我是C编程新手。因此,我确定有些东西我不见了。
如果需要任何其他信息,请告诉我,我们将不胜感激!
谢谢您的时间。
我不知道什么是最好的方法,但是我想你想要这样的东西。
char
char *prependstr(char *str, const char *pstr)
{
size_t pstrlen = strlen(pstr);
memmove(str + pstrlen, str, strlen(str) + 1);
memcpy(str,pstr, pstrlen);
return str;
}
int main()
{
char x[256] = "";
char pstr[] = "Hello00!!";
int i = 0;
do
{
sprintf(pstr, "Hello%02d!!", i++);
printf("%s\n", prependstr(x,pstr));
}while(strlen(pstr) + strlen(x) + 1 < sizeof(x));
}
这是我最初发布的功能的变更版本,似乎可以用于我的情况:
https://godbolt.org/z/Lx5U6D
以下是更改:
我使用void shiftChar(char *arr, int size, int dataLen)
{
for (int i = (dataLen - 1); i >= 0; i--)
{
memmove(arr + i + size, arr + i, 1);
}
for (int i = 0; i < size; i++)
{
memcpy(arr + i, "0", 1);
}
}
将现有数据向右移memmove()
,然后将x
填充为0的前memcpy()
个字节。
而不是x
循环将数据从0移到数据长度(负1),我从数据长度(负1)移到0。这是因为元素已经被替换为已经替换的数据, for
参数的值。
我不检查有关函数超出尺寸的任何错误。我打算在使用该功能之前执行此操作。
这里是完整的测试程序:
size
这是输出:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void shiftChar(char *arr, int size, int dataLen)
{
for (int i = (dataLen - 1); i >= 0; i--)
{
memmove(arr + i + size, arr + i, 1);
}
for (int i = 0; i < size; i++)
{
memcpy(arr + i, "0", 1);
}
}
struct struct1
{
char str[10];
int myNum;
};
struct struct2
{
char str[5];
};
int main()
{
char buffer[256];
struct struct1 *struct1 = (struct struct1 *) (buffer);
struct struct2 *struct2 = (struct struct2 *) (buffer + sizeof(struct struct1));
struct1->myNum = 5;
strncpy(struct1->str, "Hello!", 6);
strncpy(struct2->str, "TST", 3);
fprintf(stdout, "Buffer => ");
for (int i = 0; i < (sizeof (struct struct1) + sizeof(struct struct2)); i++)
{
fprintf(stdout, "%c", buffer[i]);
}
fprintf(stdout, "\n\n");
shiftChar(buffer, 6, sizeof(struct struct1) + sizeof(struct struct2));
fprintf(stdout, "New Buffer => ");
for (int i = 0; i < 6 + (sizeof (struct struct1) + sizeof(struct struct2)); i++)
{
fprintf(stdout, "%c", buffer[i]);
}
struct1 = (struct struct1 *) (buffer + 6);
struct2 = (struct struct2 *) (buffer + sizeof(struct struct1) + 6);
fprintf(stdout, "\n\nstruct1->str => %s\n", struct1->str);
exit(0);
}
感谢@P__J__和@Lee Daniel Crocker推荐Buffer => Hello!����TST
New Buffer => 000000Hello!����TST
struct1->str => Hello!
和memmove()
!
如果您看到任何可以改进的地方,请随时发表评论!
谢谢。
除非您将memcpy()
限制为nul-terminated C字符串,否则您需要再进行一些检查,以确保仅将数组中已初始化的字符移动不超过元素保留在数组中右侧的字符。另外,除非您具有nul-terminated C字符串,否则您将不能依靠arr
来获取数组中的字符数。您将必须将该参数作为附加参数传递,否则将调用Undefined Behavior,将未终止的数组传递给strlen()
。
[在编写可在有限存储量内进行任何操作的函数时,它通常有助于抓住铅笔和纸张并绘制出要使用的内容并标记所需的变量(纸张和铅笔比ASCII字体快得多) 。没什么花哨的,但是您可以使用类似的东西:
strlen()
哪个可以让您仔细考虑您尝试执行的操作的限制。上面给出给定的 |<--------------- size ---------------->|
| |
+---+---+---+---+---+---+---+---+---+---+
| a | b | c | d | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
|<---- nchr --->|
|<- shift ->|
元素数组,其中包含size
个字符,如果要将内容移位nchr
个元素,则可用的最大移位为shift
个元素。否则,您将超出数组范围。此外,如果您尝试将元素移位零,则没有理由执行任何测试,只需返回错误即可。
通过最小限度的测试来限制移位而不响应零移位,您可以执行以下操作:
size - nchr
循环尝试在int shiftchar (char *arr, size_t size, size_t nchr, size_t shift)
{
size_t max = size - nchr; /* max shift is size - no. of filled chars */
if (!shift) { /* validate positive shift */
fputs ("error: zero shift requested\n", stderr);
return 0; /* return failure */
}
if (shift > max) { /* check if shift exceeds no. of chars available */
fputs ("error: shift exceeds array bounds\n", stderr);
return 0; /* return failure */
}
memmove (&arr[shift], arr, shift); /* shift chars in arr to right */
return 1; /* return success */
}
元素字符数组中的0
和9
元素之间进行转换的简短示例可能是:
10
示例使用/输出
如果我理解您的规范,则仅在有可能在不超出范围的情况下移动数组中的该数量的字符时才应完成转换,否则返回错误:
#include <stdio.h>
#include <string.h>
int shiftchar (char *arr, size_t size, size_t nchr, size_t shift)
{
size_t max = size - nchr; /* max shift is size - no. of filled chars */
if (!shift) { /* validate positive shift */
fputs ("error: zero shift requested\n", stderr);
return 0; /* return failure */
}
if (shift > max) { /* check if shift exceeds no. of chars available */
fputs ("error: shift exceeds array bounds\n", stderr);
return 0; /* return failure */
}
memmove (&arr[shift], arr, shift); /* shift chars in arr to right */
return 1; /* return success */
}
int main (void) {
for (size_t i = 0; i < 10; i++) {
char arr[10] = "0123456789";
if (shiftchar (arr, 10, i, i)) {
memset (arr, 'z', i);
printf ("%.10s\n", arr);
}
}
}
将这些想法与您收到的其他答案结合在一起,您应该能够编写出满足所有需求的移位功能。还要记住,如果要处理$ ./bin/shiftchar
error: zero shift requested
z023456789
zz01456789
zzz0126789
zzzz012389
zzzzz01234
error: shift exceeds array bounds
error: shift exceeds array bounds
error: shift exceeds array bounds
error: shift exceeds array bounds
以外的内容,则需要将移位的字节数乘以该数量,例如
char
让我知道是否还有其他问题。