我正在动态分配2D数组:
char ** inputs;
inputs = (char **) malloc(4 * sizeof(char));
执行此操作后,我开始遇到字符串问题。我在分配2D数组之前和之后打印了字符串:
printf("%s\n", str);
char ** inputs;
inputs = (char **) malloc(4 * sizeof(char));
printf("%s\n", str);
但我得到了奇怪的输出:
before: input aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa with len 34
after: input aaaaaaaaaaaaaaaaaaaaaaaaaaaa with len 29
为什么长度会改变?我已经搜索了stackoverflow和其他网站,但无法找到合理的答案。
这是我的所有函数调用:
int main(int argc, char const *argv[])
{
/* code */
mainProcess();
printf("\nEnd of the program\n");
return 0;
}
// Reading the input from the user
char * getInput(){
printf("Inside of the getInput\n");
char * result;
char * st;
char c;
result = malloc(4 * sizeof(char));
st = malloc(4 * sizeof(char));
// code goes here
printf("$ ");
while(3){
c = fgetc(stdin);
if(c == 10){
break;
}
printf("%c", c);
result[length] = c;
length++;
}
result[length] = '\0';
return result;
}
void mainProcess(){
char * input;
printf("Inside of Main process\n");
input = getInput();
printf("\nthis is input %s with len %d\n", input, strlen(input));
splitInput(input);
printf("\nthis is input %s with len %d\n", input, strlen(input));
}
char ** splitInput(const char * str){
char ** inputs;
inputs = NULL;
printf("inside split\n");
printf("%s\n", str);
inputs = (char **) malloc( sizeof(char));
// free(inputs);
printf("------\n"); // for testing
printf("%s\n", str);
if(!inputs){
printf("Error in initializing the 2D array!\n");
exit(EXIT_FAILURE);
}
return NULL;
}
答案 0 :(得分:3)
您要完成的内容并不完全清楚,但似乎您尝试使用getInput
阅读一行文字,然后您打算将输入分为splitInput
中的单个字词,但不清楚如何去做。将一行文本分成单词的过程称为标记一个字符串。标准库提供strtok
(恰当命名)和strsep
(如果您有可能空分隔字段,则主要有用)。
我已经在上面的评论中解释了2D数组与你使用指针指向字符之间的区别。
首先,请查看getInput
。 c
必须是int
类型,或者您无法检测EOF
,这个问题不会让您感到悲伤。此外,您只需将指针(类型size_t
)作为参数传递,并在result
中保留字符数,并避免strlen
获取返回字符串的长度。无论如何你必须使用一个计数器来确保你不要在result
的末尾开始写作,所以你也可以在调用函数中重新计算,例如。
char *getInput (size_t *n)
{
printf ("Inside of the getInput\n");
char *result = NULL;
int c = 0; /* c must be type 'int' or you cannot detect EOF */
/* validate ALL allocations */
if ((result = malloc (MAXC * sizeof *result)) == NULL) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return result;
}
printf ("$ ");
fflush (stdout); /* output is buffered, flush buffer to show prompt */
while (*n + 1 < MAXC && (c = fgetc (stdin)) != '\n' && c != EOF) {
printf ("%c", c);
result[(*n)++] = c;
}
putchar ('\n'); /* tidy up with newline */
result[*n] = 0;
return result;
}
接下来,如上所示,您似乎想要使用result
中的文本行并使用splitInput
填充指向指针的指针使用单个单词(您会混淆为2D数组)。要做到这一点,您必须牢记strtok
将修改其操作的字符串,因此您必须复制str
作为const char *
传递的内容避免尝试修改常量字符串(和segfault)。
您对如何分配指针指向char对象感到困惑。首先,您必须为足够数量的指针分配空间,例如(使用#define MAXW 32
)你需要这样的东西:
/* allocate MAXW pointers */
if ((inputs = malloc (MAXW * sizeof *inputs)) == NULL) {
fprintf (stderr, "error: memory exhausted - inputs.\n");
return inputs;
}
然后,当您对输入字符串进行标记时,必须为每个单独的单词分配(每个单词本身都是一个单独的字符串),例如
if ((inputs[*n] = malloc ((len + 1) * sizeof *inputs[*n])) == NULL) {
fprintf (stderr, "error: memory exhausted - word %zu.\n", *n);
break;
}
strcpy (inputs[*n], p);
(*n)++;
注意: 'n'
是一个指向size_t
的指针,可以在调用者中恢复字数。
要标记输入字符串,您可以将上面的分配包装在:
中 for (char *p = strtok (cpy, delim); p; p = strtok (NULL, delim))
{
size_t len = strlen (p);
...
if (*n == MAXW) /* check if limit reached */
break;
}
在整个代码中,您还应验证所有内存分配,并为每个分配的函数提供有效的返回,以允许调用者验证被调用函数是成功还是失败。
将所有部分组合在一起,您可以执行以下操作:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXC 256 /* constant for maximum characters of user input */
#define MAXW 32 /* constant for maximum words in line */
void mainProcess();
int main (void)
{
mainProcess();
printf ("End of the program\n");
return 0;
}
char *getInput (size_t *n)
{
printf ("Inside of the getInput\n");
char *result = NULL;
int c = 0; /* c must be type 'int' or you cannot detect EOF */
/* validate ALL allocations */
if ((result = malloc (MAXC * sizeof *result)) == NULL) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return result;
}
printf ("$ ");
fflush (stdout); /* output is buffered, flush buffer to show prompt */
while (*n + 1 < MAXC && (c = fgetc (stdin)) != '\n' && c != EOF) {
printf ("%c", c);
result[(*n)++] = c;
}
putchar ('\n'); /* tidy up with newline */
result[*n] = 0;
return result;
}
/* split str into tokens, return pointer to array of char *
* update pointer 'n' to contain number of words
*/
char **splitInput (const char *str, size_t *n)
{
char **inputs = NULL,
*delim = " \t\n", /* split on 'space', 'tab' or 'newline' */
*cpy = strdup (str);
printf ("inside split\n");
printf ("%s\n", str);
/* allocate MAXW pointers */
if ((inputs = malloc (MAXW * sizeof *inputs)) == NULL) {
fprintf (stderr, "error: memory exhausted - inputs.\n");
return inputs;
}
/* split cpy into tokens (words) max of MAXW words allowed */
for (char *p = strtok (cpy, delim); p; p = strtok (NULL, delim))
{
size_t len = strlen (p);
if ((inputs[*n] = malloc ((len + 1) * sizeof *inputs[*n])) == NULL) {
fprintf (stderr, "error: memory exhausted - word %zu.\n", *n);
break;
}
strcpy (inputs[*n], p);
(*n)++;
if (*n == MAXW) /* check if limit reached */
break;
}
free (cpy); /* free copy */
return inputs;
}
void mainProcess()
{
char *input = NULL,
**words = NULL;
size_t len = 0, nwords = 0;
printf ("Inside of Main process\n\n");
input = getInput (&len);
if (!input || !*input) {
fprintf (stderr, "error: input is empty or NULL.\n");
return;
}
printf ("this is input '%s' with len: %zu (before split)\n", input, len);
words = splitInput (input, &nwords);
printf ("this is input '%s' with len: %zu (after split)\n", input, len);
free (input); /* done with input, free it! */
printf ("the words in input are:\n");
for (size_t i = 0; i < nwords; i++) {
printf (" word[%2zu]: '%s'\n", i, words[i]);
free (words[i]); /* free each word */
}
free (words); /* free pointers */
putchar ('\n'); /* tidy up with newline */
}
示例使用/输出
$ ./bin/mainprocess
Inside of Main process
Inside of the getInput
$ my dog has fleas
my dog has fleas
this is input 'my dog has fleas' with len: 16 (before split)
inside split
my dog has fleas
this is input 'my dog has fleas' with len: 16 (after split)
the words in input are:
word[ 0]: 'my'
word[ 1]: 'dog'
word[ 2]: 'has'
word[ 3]: 'fleas'
End of the program
内存错误检查
在您编写的任何动态分配内存的代码中,您需要通过内存/错误检查程序运行代码。在Linux上,valgrind
是正常选择。只需通过它运行代码,例如
$ valgrind ./bin/mainprocess
==15900== Memcheck, a memory error detector
==15900== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==15900== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==15900== Command: ./bin/mainprocess
==15900==
Inside of Main process
Inside of the getInput
$ my dog has fleas
my dog has fleas
this is input 'my dog has fleas' with len: 16 (before split)
inside split
my dog has fleas
this is input 'my dog has fleas' with len: 16 (after split)
the words in input are:
word[ 0]: 'my'
word[ 1]: 'dog'
word[ 2]: 'has'
word[ 3]: 'fleas'
End of the program
==15900==
==15900== HEAP SUMMARY:
==15900== in use at exit: 0 bytes in 0 blocks
==15900== total heap usage: 7 allocs, 7 frees, 546 bytes allocated
==15900==
==15900== All heap blocks were freed -- no leaks are possible
==15900==
==15900== For counts of detected and suppressed errors, rerun with: -v
==15900== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认您已释放所分配的内存,并且没有内存错误。
仔细看看,如果您有任何疑问,请告诉我。如果我猜错了你的意图,那么MCVE帮助:)
答案 1 :(得分:1)
此代码在没有警告的情况下编译(gcc -Wall
),并且不会更改大小
它还试图强调分配足够空间和/或不要在分配的内存之外写入的需要
注意例如
malloc((MaxInputLength+1) * sizeof(char))
while(length<MaxInputLength)
inputs[i]=malloc((MaxLengthOfSplitString+1) * sizeof(char));
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// the length which was used in your MCVE, probably accidentally
#define MaxInputLength 3 // you will probably want to increase this
#define MaxLengthOfSplitString 1 // and this
#define MaxNumberOfSplitStrings 3 // and this
// Reading the input from the user
char * getInput(){
printf("Inside of the getInput\n");
char * result;
char c;
int length=0;
result = malloc((MaxInputLength+1) * sizeof(char));
// code goes here
printf("$ ");
while(length<MaxInputLength){
c = fgetc(stdin);
if(c == 10){
break;
}
printf("%c", c);
result[length] = c;
length++;
}
result[length] = '\0';
return result;
}
char ** splitInput(const char * str){
char ** inputs;
inputs = NULL;
printf("inside split\n");
printf("%s\n", str);
inputs = (char **) malloc(MaxNumberOfSplitStrings * sizeof(char*));
{
int i;
for (i=0; i< MaxNumberOfSplitStrings; i++)
{
inputs[i]=malloc((MaxLengthOfSplitString+1) * sizeof(char));
}
// Now you have an array of MaxNumberOfSplitStrings char*.
// Each of them points to a buffer which can hold a ero- terminated string
// with at most MaxLengthOfSplitString chars, ot counting the '\0'.
}
// free(inputs);
printf("------\n"); // for testing
printf("%s\n", str);
if(!inputs){
printf("Error in initializing the 2D array!\n");
exit(EXIT_FAILURE);
}
return NULL;
}
void mainProcess(){
char * input;
printf("Inside of Main process\n");
input = getInput();
printf("\nthis is input %s with len %d\n", input, strlen(input));
splitInput(input);
printf("\nthis is input %s with len %d\n", input, strlen(input));
}
int main(int argc, char const *argv[])
{
/* code */
mainProcess();
printf("\nEnd of the program\n");
return 0;
}