gpt4 book ai didi

c - 为什么我的程序在运行时崩溃

转载 作者:行者123 更新时间:2023-11-30 19:05:18 25 4
gpt4 key购买 nike

我必须编写一个程序,通过移动句子来输入要加密的句子。我必须先将句子转移到2D数组,其大小必须是一个完美的正方形,以最大化所需的空间。 (例如,如果句子中的字符数为54,则数组的大小将为8,而不是7,因为它适合整个句子)。句子中的空格和空值应替换为下划线。然后我需要该数组向左移动,但是它崩溃了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>


void printArray (int size, char block [size][size])
{
int row, col;
for (row = 0; row < size; row++)
{
printf("\n");
for (col = 0; col < size; col++)
{
printf("%c", block[row][col]);
}
}
}

int main ()
{
// Sentence is "Patience is a minor form of despair disguised as a virtue."

char sentence [1000];
printf("Please enter a sentence to be encrypted: ");
gets (sentence);

int numOfChar = strlen(sentence);
int size = 1;
while (size <= (numOfChar/size))
{
size++;
}
printf("\nThe number of chars is %d and the size is %d", numOfChar, size);


int n = (size * size) - numOfChar; // fills the
empty values with "_"'s
char fillBlank [n];
int i;
for (i = 0; i < n; i++)
{
fillBlank[i] = '_';
}
strcat(sentence, fillBlank);

// ------------------------------------------------ Makes the array ------------------------------------------- //

char block [size][size];
int row;
int col;
int counter = 0;

while (counter < (size * size))
{
for (row = 0; row < size; row++)
{
for (col = 0; col < size; col++)
{
if (sentence [counter] == ' ')
block [row][col] = '_';
else if (sentence[counter] == '\0')
block [row][col] = '_';
else
block [row][col] = sentence [counter];
counter++;
}
}
}

// ------------------------------------------- Prints the array --------------------------------------------- //

printArray(size, block [size][size]);
/*
for (row = 0; row < size; row++)
{
printf("\n");
for (col = 0; col < size; col++)
{
printf("%c", block[row][col]);
}
}
*/
// ------------------------------------------- Shifts the array left --------------------------------------- //

printf("\n\n\n");
char temp [size];
col = 0;
for (row = 0; row < size; row++)
{
temp [row] = block [row][col];
}

for (row = 0; row < size; row++)
{
for (col = 0; col < size; col++)
{
block [row][col] = block [row][col+1];
}
}

col = 7;
for (row = 0; row < size; row++)
{
block [row][col] = temp [row];
}

printArray(size, block [size][size]);
/*
for (row = 0; row < size; row++)
{
printf("\n");
for (col = 0; col < size; col++)
{
printf("%c", block[row][col]);
}
}
*/
return 0;
}

最佳答案

首先,您需要学习计数,句子中包含58-characters,其次,您使自己变得比原本要难得多。

如果我理解您的问题,您想:


阅读用户输入的句子;
确定长度;
修改句子并将所有spaces替换为'_'(下划线);
形成一个最小大小足以容纳句子中字符的正方形数组(例如58个字符,需要8x8数组);
用修改后的句子填充正方形数组,并在句子的最后一个字符之后用下划线填充该数组的所有空白元素;和
将数组中的每一行向左移动1个字符,将第一个字符移到先前由最后一个字符占据的位置。


您已经包含了提供memset memcpymemmove的必要标头-这将大大简化您的任务。

首先,如注释中所述,永远不要使用gets。它是如此不安全并且容易被缓冲区溢出利用,因此已从C11标准库中完全删除。请改用fgets,例如:

#define MAXS 1024   /* if you need a constant - define one (or more) */
...
char sentence [MAXS] = "";
size_t i, len = 0, size;

fputs ("Please enter a sentence to be encrypted:\n", stdout);
if (!fgets (sentence, MAXS, stdin)) { /* read/validate sentence */
fputs ("error: user canceled input or EOF\n", stderr);
return 1;
}


接下来,使用 fgets时,它将最多读取(包括)用户按Enter生成的尾随换行符( '\n')。您需要从句子中删除结尾的 '\n'。您可以通过在 length - 1处简单检查字符来完成此操作。如果它是 '\n',则只需用nul字符( '\0'或等效的 0)覆盖它。

如果最后一个字符不是 '\n',则需要检查字符串( -1)的长度是否是字符串可以容纳的最大长度。如果您已存储了最大数量的字符,而最后一个字符不是 '\n' -则表明用户输入的字符超出了缓冲区可容纳的字符数–意味着 stdin中的某些字符尚未读取- -相应地处理,例如

    len = strlen (sentence);                /* get sentence length */
if (len && sentence[len - 1] == '\n') /* is last char '\n' ? */
sentence[--len] = 0; /* overwrite with nul-char */
else if (len == MAXS - 1) { /* otherwise - input exceeds MAXS chars */
fprintf (stderr, "error: string exceeds %d chars.\n", MAXS);
return 1;
}


您如何根据句子的字符数( len)确定所需的方阵大小?长度(作为整数值)+1的平方根非常简单:

    size = (size_t)sqrt(len);   /* set size (trucation intentional) */
if (len % size)
size += 1;


您也可以在此时完成对句子的修改,将所有 spaces替换为 '_',例如

    for (i = 0; i < len; i++)       /* replace ' ' with '_' */
if (sentence[i] == ' ')
sentence[i] = '_';


现在,您需要做的就是将 block声明为2D VLA(如果没有VLA扩展名,则可以声明一个指向char的指针,并分配 size个指针,并分配一个使用 sizemalloc字符分配给每个指针。由于您的原始代码使用的是VLA,因此我们将继续使用。

声明您的VLA之后,您需要做的所有事情以用修饰词填充它,以确保所有其他未使用的元素都是下划线,是在将数组的修饰词 memset之前对所有 '_'数组 memcpy,例如:

    char block[size][size];             /* declare VLA */
memset (block, '_', size * size); /* set all to '_' */
memcpy (block, sentence, len); /* copy sentence to block */


而已。剩下的就是将每一行向左移动1个字符。这可以通过简单地将每行中的第一个字符保存在临时变量中,然后使用 memmove将行中的每个字符左移1,然后将行中的最后一个字符设置为您保存的临时字符来实现。 (您应该使用 memmove而不是 memcpy,因为源和目标内存重叠),例如

    /* shift the array left */
for (i = 0; i < size; i++) {
char tmp = *block[i]; /* save 1st char in row */
memmove (block[i], &block[i][1], size - 1); /* shift row left by 1 */
block[i][size - 1] = tmp; /* put 1st char as last */
}


如果我对您的理解正确,那么您要做的就是完成您在问题中陈述的内容。综上所述,您可以执行以下操作:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MAXS 1024 /* if you need a constant - define one (or more) */

void printarray (int size, char block [size][size])
{
int row, col;

for (row = 0; row < size; row++) {
for (col = 0; col < size; col++)
putchar (block[row][col]); /* don't use printf to output */
putchar ('\n'); /* a single-character */
}
}

int main (void) {

/* sentence is:
* "Patience is a minor form of despair disguised as a virtue."
*/
char sentence [MAXS] = "";
size_t i, len = 0, size;

fputs ("Please enter a sentence to be encrypted:\n", stdout);
if (!fgets (sentence, MAXS, stdin)) { /* read/validate sentence */
fputs ("error: user canceled input or EOF\n", stderr);
return 1;
}
len = strlen (sentence); /* get sentence length */
if (len && sentence[len - 1] == '\n') /* is last char '\n' ? */
sentence[--len] = 0; /* overwrite with nul-char */
else if (len == MAXS - 1) { /* otherwise - input exceeds MAXS chars */
fprintf (stderr, "error: string exceeds %d chars.\n", MAXS);
return 1;
}
printf ("\nsentence: '%s'\n\n", sentence); /* output sentence */

size = (size_t)sqrt(len); /* set size (trucation intentional) */
if (len % size)
size += 1;
printf("The number of chars is %zu and the size is %zu\n\n", len, size);

for (i = 0; i < len; i++) /* replace ' ' with '_' */
if (sentence[i] == ' ')
sentence[i] = '_';

char block[size][size]; /* declare VLA */
memset (block, '_', size * size); /* set all to '_' */
memcpy (block, sentence, len); /* copy sentence to block */

printf ("block array:\n\n"); /* output original block array */
printarray (size, block);

/* shift the array left */
for (i = 0; i < size; i++) {
char tmp = *block[i]; /* save 1st char in row */
memmove (block[i], &block[i][1], size - 1); /* shift row left by 1 */
block[i][size - 1] = tmp; /* put 1st char as last */
}

printf ("\n\nshifted block array:\n\n");
printarray (size, block);

return 0;
}


(注意:如果您使用的是windoze,请用 %zu替换所有 %lu格式说明符,因为Windows不会为 z提供 size_t修饰符)

使用/输出示例

$ ./bin/array_block_shift
Please enter a sentence to be encrypted:
Patience is a minor form of despair disguised as a virtue.

sentence: 'Patience is a minor form of despair disguised as a virtue.'

The number of chars is 58 and the size is 8

block array:

Patience
_is_a_mi
nor_form
_of_desp
air_disg
uised_as
_a_virtu
e.______


shifted block array:

atienceP
is_a_mi_
or_formn
of_desp_
ir_disga
ised_asu
a_virtu_
.______e




memxxx功能等效项

鉴于您对 memxxx函数的评论和问题以及您正在自学,您可能会受益于仅使用简单循环而不是 memsetmemcpy和< cc>。尽管使用久经考验的真正的库函数总能带来更好的收益,但是剥开封面并查看其内部功能有很大的学习价值。

一注。 memmovememcpy实际上可以做同样的事情,但是 memmove仅在副本的 memcpysource不重叠的地方定义。 destination对于确实重叠的区域是安全的。因此,在您的情况下,由于区域重叠,因此我们需要将元素 memmove留给 1, 2, 3 ... 8复制到 0, 1, 2 ... 7处,因此需要使用 memmove

建议-始终在启用警告的情况下进行编译-使用 man pages

另外,示例前的最后一条注释始终在启用警告的情况下进行编译,并且在不进行警告的情况下进行编译之前不接受代码。您应该使用的最低警告为 -Wall -Wextra(并且还应该添加 -pedantic来添加一些其他警告)。我还建议 -Wshadow捕获可能导致问题的任何意外阴影变量。

每次编译时,都应使用这些选项作为编译字符串的一部分进行编译。如果在使用VS( cl.exe)的Windows上,则至少使用 /W3(您可以使用 /wdXXXX禁用Windows上的特定警告,其中 XXXX是要禁用的警告代码)

阅读并理解每个警告。是的,请花一些时间阅读和理解每一本书。提供对问题的简要说明,并提供发生问题的行号。去地址每个。您可以通过听大多数教程中编译器告诉您的内容来学习尽可能多的C语言。

(gcc / clang警告远远优于VS提供的警告,并且在VS中,如果启用 /Wall,则会得到许多与编译器相关的常规警告,这些警告不是针对代码的警告,其中有1/2打 可以简化为与您的代码相关的内容)

如以下注释中所述,如果您使用的是Linux / Unix,则 /wdxxxx会提供有关每个C库函数的详细用法信息。使用它们。只需打开终端,然后输入例如 man pages即可了解 man memmove功能。学习时(甚至在您认为自己已经学习过某个功能之后),如果对如何使用它或使用合适的参数有疑问,请始终咨询 memmove,最重要的是,它在成功时会返回什么值以及成功时会返回什么值返回以指示失败(以及是否在 man functionname中设置了其他信息,可以使用 errno进行检索-打印错误)。如果您仅合并使用这些可用的基本工具,就可以将学习的挫败感降低十倍,并且比以往任何时候都快几年。

在示例中,它确实执行了上面的代码,但是消除了对 perror()的所有依赖(这将使您了解为什么它们可以简化您的生活)

#include <stdio.h>
#include <string.h>

#define MAXS 1024 /* if you need a constant - define one (or more) */

void printarray (int size, char block [size][size])
{
int row, col;

for (row = 0; row < size; row++) {
for (col = 0; col < size; col++)
putchar (block[row][col]); /* don't use printf to output */
putchar ('\n'); /* a single-character */
}
}

int main (void) {

/* sentence is:
* "Patience is a minor form of despair disguised as a virtue."
*/
char sentence [MAXS] = "";
size_t i, j, len = 0, size;

fputs ("Please enter a sentence to be encrypted:\n", stdout);
if (!fgets (sentence, MAXS, stdin)) { /* read/validate sentence */
fputs ("error: user canceled input or EOF\n", stderr);
return 1;
}
len = strlen (sentence); /* get sentence length */
if (len && sentence[len - 1] == '\n') /* is last char '\n' ? */
sentence[--len] = 0; /* overwrite with nul-char */
else if (len == MAXS - 1) { /* otherwise - input exceeds MAXS chars */
fprintf (stderr, "error: string exceeds %d chars.\n", MAXS);
return 1;
}
printf ("\nsentence: '%s'\n\n", sentence); /* output sentence */

if (len < 4) {
fputs ("error: sentence less than 4 chars - too short.\n", stderr);
return 1;
}
for (size = 2; size * size < len; size++) {} /* set size */
printf("The number of chars is %zu and the size is %zu\n\n", len, size);

for (i = 0; i < len; i++) /* replace ' ' with '_' */
if (sentence[i] == ' ')
sentence[i] = '_';

char block[size][size]; /* declare VLA */
for (i = 0; i < size; i++) /* initialize all element '_' */
for (j = 0; j < size; j++) /* (memset (block, '_', size) */
block[i][j] = '_';

size_t n = 0;
for (i = 0; i < size; i++) /* copy sentence to block */
for (j = 0; j < size; j++) /* (memcpy (block, sentence, len) */
if (n < len)
block[i][j] = sentence[n++];
else
break;

printf ("block array:\n\n"); /* output original block array */
printarray (size, block);

/* shift the array left (memmove (block[i], &block[i][1], size - 1)) */
for (i = 0; i < size; i++) {
char tmp = block[i][0]; /* save 1st char in row */
for (j = 1; j < size; j++)
block[i][j-1] = block[i][j];
block[i][size - 1] = tmp; /* put 1st char as last */
}

printf ("\n\nshifted block array:\n\n");
printarray (size, block);

return 0;
}


注意:要更紧密地模拟 memxxx的实际作用,可以使用:

for (i = 0; i < len; i++)           /* copy sentence to block */
(*block)[i] = sentence[i]; /* (memcpy (block, sentence, len) */


但是请注意,这仅适用于保证 memcpy (block, sentence, len)小于 len的2D数组。此外,它不适用于您为 size * size分配了每个 char **个字符的 size指针的情况。为什么?只有一个数组可以保证所有元素在内存中都是顺序的。当使用指针集合和独立分配的内存块来模拟2D数组时,无法保证。

使用/输出完全相同。

仔细研究一下,如果我误解了您的目标,或者您还有其他问题,请告诉我。

关于c - 为什么我的程序在运行时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50126709/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com