在字符数组中向右移动字符的最佳方法

问题描述 投票:0回答:3

我正在尝试在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`����

我知道我做错了,但是我不确定我做错了什么,或者我是否应该对此做不同的处理。

我的主要问题是:

  1. shiftChar()函数我在做什么错?

  2. 是否有更好/更轻松的方法来实现我正在尝试的目标?

  3. 是否可以检查char数组中的元素是否具有垃圾值(例如,尚未填写的值)?我想我可以使用0之类的东西将缓冲区设置为所有memset(),但是如果我有一个int指向值为'0'的缓冲区数据的结构,会发生什么。我想如果我检查该值是否等于“ 0”,那么该偏移将被排除在外。

我也对此进行了研究,但是我遇到的大多数线程都是C ++或将元素向左移动。我无法为我的问题找到可靠的解决方案。我将在另一个正在使用的程序中使用该解决方案(如果有),我将需要在开始时将struct iphdr的大小添加到现有的缓冲区char中(数据已经通过struct iphdr和[ C0]),这样我就可以创建和发送IPIP数据包(网络编程)。我也知道我可以制作一个全新的char并仅从旧缓冲区复制数据(同时使第一个struct udphdr元素保持空闲),但是我想这对我的情况会造成很大的性能影响,因为将不得不每秒执行数千次此操作,最好只修改现有缓冲区sizeof(struct iphdr)

我是C编程新手。因此,我确定有些东西我不见了。

如果需要任何其他信息,请告诉我,我们将不胜感激!

谢谢您的时间。

c char shift
3个回答
1
投票

我不知道什么是最好的方法,但是我想你想要这样的东西。

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)); }


0
投票

这是我最初发布的功能的变更版本,似乎可以用于我的情况:

https://godbolt.org/z/Lx5U6D

以下是更改:

  1. 我使用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()个字节。

  2. 而不是x循环将数据从0移到数据长度(负1),我从数据长度(负1)移到0。这是因为元素已经被替换为已经替换的数据, for参数的值。

  3. 我不检查有关函数超出尺寸的任何错误。我打算在使用该功能之前执行此操作。

这里是完整的测试程序:

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()

如果您看到任何可以改进的地方,请随时发表评论!

谢谢。


0
投票

除非您将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 */ } 元素字符数组中的09元素之间进行转换的简短示例可能是:

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

让我知道是否还有其他问题。

© www.soinside.com 2019 - 2024. All rights reserved.