Can I convert char*[20] to char[][20]?

血红的双手。 提交于 2019-12-08 14:24:16

问题


I've corrected the program by myself now. this is still the -Never- answered question: I have a 2D array of chars that will contain a word every array. I split a char* word by word with a function to place them in the array. My problem is that it doesn't print the word but random characters. May it be a problem of pointers? I'm not sure about the conversion of char*[20] to char[][20] because I want filter a char*spamArray[20] into a char[][20]

I need to pass char*[20] to the filter which has an argument char[][20].

This is the call:

char* spam = "this is a string";
//spam isn't actually initialized this way, but this is just for explaining what it contains

//OLD QUESTION CODE:char (*spamArray)[20]  = (char(*)[20])malloc((sizeof(char) * 20) * nSpam);
//new:
char spamArray[nSpam][20];
//nSpam is the number of words

splitstring(spam, &spamArray[0], nSpam);

This is the function splitstring into words

inline void splitstring(char *str, char (*arr)[20], size_t t)
{
    size_t i = 0;   //index char nella stringa dell'array
    while(t != 0)
    {
        if (*str != ' ' && *str != '\0')
        {
            (*arr)[i] = *str;
            *str++;
            i++;
        }
        else
        {
            t--;
            *str++;
            (*arr)[i] = '\0';
            *arr++;
            i = 0;
        }
    }
}

then I'll call a function which is for testing and printing the words in the 2D array (spamArray)

filter_mail(&txt, spamArray) //i call the function this way

void filter_mail(char **line, char spam[][20], int nSpam)
{
    char *line_tmp = *line;
    bool isSpam = 0;

    int a = 0;
    int c = 0;

    while(nSpam!= 0)
    {
        if (spam[a][c] != '\0')
        {
            printf("%c", spam[a][c]);
            c++;
        }
        else
        {
            a++;
            c = 0;
            nSpam--;
        }
    }
}

Then it prints random things every time and the program crashes. Also, how should I free a spamArray? is it correct to free it this way?

free(spamArray)

I haven't got any answer right now because everyone pointed out that using char[][] doesn't work. Well of course it doesn't. I don't even use it in the source code. That was just the title of the question. Please read everything before any other answer.


回答1:


i have a 2D Array

No, you don't. 2D arrays don't exist in C99 or C11, and don't exist in C++11. BTW, even if C++17 added more containers to the C++11 and C++14 standards, they did not add matrixes.

Arrays (both in C and in C++) are always unidimensional. In some weird cases, you could have arrays of arrays (each component should have the same type, so same dimension, same size, same alignment), but this is so confusing that you should not even try.

(and your code and your numerous comments show that you are very confused. It is OK, programming is difficult to learn; you need years of work)

Can i convert char*[] to char[][]?

No, because the char[][] type does not exist and cannot exist (both in C++11 or C++14 and in C99 or C11) because arrays should have elements of the same fixed and known size and type.

Look into existing libraries (such as Glib), at least for inspiration. Study the source code of relevant free software projects (e.g. on github).

Beware of undefined behavior; it may happen that a code (like yours) is wrong but don't crash properly. Be scared of UB!

Then it prints random things every time and the program crashes

Typical case of UB (probably elsewhere in your code). You are lucky to observe a crash. Sometimes UB is much more insidious.

coding in C99 or C11

First, spend more time in reading documentation. Read several books first. Then look into some reference site. At last, read carefully the n1570 standard of C11. Allocate a week of dense work for that purpose (and don't touch your code at all during that time; perhaps carry on some tiny experiments on toy code unrelated to your project and use the debugger to understand what is going on in the computer).

You may have an array of 16-byte wide strings; I often don't do that, but if I did I prefer to name intermediate types:

 typedef char sixteenbytes_ty[16];
 extern sixteenbytes_ty array[];

You might code extern char array[][16]; but that is so confusing that I got it wrong -because I never do that- and you really should never code that.

This declares a global array containing elements of 16 bytes arrays. Again, I don't recommend doing that.

As a rule of thumb: never use so called "2D arrays" (in reality arrays of arrays) in C. If you need matrixes of variable dimensions (and you probably don't) implement them as an abstract data type like here.

If you manipulate data which happens to have 16 byte, make a struct of them:

struct mydata_st {
  char bytes[16];
};

it is much more readable.

You may have an array of pointers, e.g. char*[] (each pointer has a fixed size, 8 bytes on my Linux/x86-64 machine, which is not the same as the allocated size of the memory zone pointed by it).

You probably should start your code entirely (and throw away your code) and think in terms of abstract data types. I strongly recommend reading SICP (freely downloadable). So first, write on paper the specification (the complete list of operations, or the interface or API of your library), using some natural language like English or Italian.

Perhaps you want some kind of vector of strings, or matrix of chars (I don't understand what you want, and you probably did not specify it clearly enough on paper).

If coding in C99, consider using some flexible array members in some of your (internal) type implementations.

Perhaps you decide that you handle some array of dynamically allocated strings (each obtained by strdup or asprintf etc...).

So perhaps you want some kind of dynamic vector of dynamically allocated types. Then define first the exact list of operations on them. Read the wikipage on flexible array members. It could be very useful.


BTW, compile with all warnings and debug info, so compile with gcc -Wall -Wextra -g your C code (if using GCC). Use the debugger gdb to understand better the behavior of your program on your system, run it step by step, query the state of the debugged process.

coding in C++11 or newer

If coding in C++11 (which is not the same language as C99) use existing types and containers. Again, read some good book (like this) more documentation and reference. C++ is a very difficult programming language, so spend several weeks in reading.




回答2:


No, you can't. That's because char[][] is an array of incomplete type, thus is invalid (so it doesn't exist at all). Array elements must be of complete types, that is, the size, alignment and layout of the type must be determined at compile time.

Please stop arguing the existence of char[][]. I can assure you that it doesn't exist, at all.

Or go Google.

Fixed-length array is a candidate solution:

char[][32]

but dynamic memory allocation (with an array of pointers) is better because the size of the allocated memory is flexibly changeable. Then you can declare the function like:

void filter_mail(char **line, char spam**);

Or as suggested. At the very least, you should do it like this# (but you can't omit m):

void foo(size_t m, char (*)[m]);

You can never declare char[][] because pointer-array conversion can be done only at the top level, i.e. char*[] and char[][] (that's because of operator precedence).


I bet you don't know at all what you're doing here in splitstring():

while(t != 0)
{
    if (*str != ' ' && *str != '\0')
    {
        *arr[c] = *str;
        *str++;
        c++;
    }
    else
    {
        t--;
        *str++;
        *arr[c] = '\0';
        *arr++;
        c = 0;
    }
}

Because *arr[c] is equivalent to arr[c][0], you're just copying str to the first element in each string of arr. Get parentheses so it looks like (*arr)[c]. Then remove the asterisk before pointer increment (you don't use the value from dereferencing at all):

while(t != 0)
{
    if (*str != ' ' && *str != '\0')
    {
        (*arr)[c] = *str;
        str++;
        c++;
    }
    else
    {
        t--;
        str++;
        (*arr)[c] = '\0';
        arr++;
        c = 0;
    }

It should be fine now.


Finally, don't cast the result of malloc. Freeing spamArray with free() is just the standard way and it should be fine.




回答3:


This is a program that's a version of your program that does what you seem to want to do:

#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <stdio.h>

const int nSpam = 30;

char* spam = "this is a string";

char spamArray[30][20];
//nSpam is the number of words

void splitstring(char *str, char arr[][20], size_t nSpam)
{
   int word_num = 0;
   int char_num = 0;
   int inspace = 0;
   for (char *i = str; *i != '\0'; ++i)
   {
      if (!isspace(*i))
      {
         inspace = 0;
         assert(word_num < nSpam);
         arr[word_num][char_num++] = *i;
         assert(char_num < 20);
      }
      else
      {
         if (!inspace)
         {
            arr[word_num++][char_num] = '\0';
            char_num = 0;
            inspace = 1;
         }
      }
   }
   if (!inspace)
   {
      arr[word_num++][char_num] = '\0';
   }
   while (word_num < nSpam)
   {
      arr[word_num++][0] = '\0';
   }
}

void filter_mail(char const * const *line, char spam[][20], size_t nSpam)
{
    int a = 0;

    while (a < nSpam)
    {
       int c = 0;
       while (spam[a][c] != '\0')
       {
          printf("%c", spam[a][c++]);
       }
       printf("\n");
       ++a;
    }
}

char const * const mail_msg[] = {
   "This is a line.\n",
   "This is another line.\n",
   0
};

int main()
{
   splitstring(spam, spamArray, 30);
   filter_mail(mail_msg, spamArray, 30);
   return 0;
}

I warn you that this is a poor design that will cause you no end of problems. It's very much the wrong approach.

There is no need to free anything here because it's all statically allocated.



来源:https://stackoverflow.com/questions/47484870/can-i-convert-char20-to-char20

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!