-6

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.

PrometeoPrime
  • 81
  • 1
  • 10
  • Your fix-my-code question is off-topic here. You need to post an [MCVE] – Basile Starynkevitch Nov 25 '17 at 13:32
  • 1
    And your code is very confused, and as other's have pointed out, full of undefined behavior. You may have succeeded in getting the compiler to accept something, but that doesn't mean it does anything remotely like what you think it does. – Omnifarious Nov 26 '17 at 00:43
  • **Moderator note**: please take extended discussions to chat. Comments are not the place for them. – Martijn Pieters Nov 26 '17 at 11:24

3 Answers3

3

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.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Comments are not for extended discussion; this conversation has been [moved to chat](http://chat.stackoverflow.com/rooms/159838/discussion-on-answer-by-basile-starynkevitch-can-i-convert-char20-to-char2). – Martijn Pieters Nov 26 '17 at 11:25
1

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.

iBug
  • 35,554
  • 7
  • 89
  • 134
  • Comments are not for extended discussion; this conversation has been [moved to chat](http://chat.stackoverflow.com/rooms/159839/discussion-on-answer-by-ibug-can-i-convert-char20-to-char20). – Martijn Pieters Nov 26 '17 at 11:25
1

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.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • My version works without libraries and works with dynamic/static allocated arrays very much like a library thanks for your version anyway, i appreciate it – PrometeoPrime Nov 26 '17 at 13:13
  • 1
    @PrometeoPrime this is the last time I even participate in answering a question by someone like you. The version you had here didn't work at all. And the static data was there because a working program needs data to work with. – Omnifarious Nov 26 '17 at 14:50
  • 1
    @PrometeoPrime you're just too smart for everyone and there was never any possibility that anyone would be able to answer your question to your satisfaction. This was a colossal waste of a bunch of very competent people's time. – Omnifarious Nov 26 '17 at 14:52
  • nevermind, i think that if someone knew the right answer he would have posted it but there wasn't, the people who answered before you got the question wrong at first and they also wasted their time explaining how arrays needs to have a fixed size and that's not my problem, it's their time – PrometeoPrime Nov 26 '17 at 15:15
  • anyway, i'm not that smart, i'm sure that anyone could work with pointers if you practice with them enough – PrometeoPrime Nov 26 '17 at 15:17
  • btw the version i posted had some pointer issues that i've made the night before, i was just testing the splitstring, when i posted i didn't edit the splitstring in time so i've posted the broken version (now i've edited it with the correct one) the rest, worked correctly, there was a problem in the filter too with the printf – PrometeoPrime Nov 26 '17 at 15:28