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.
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.
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.
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.
Related
There is a line of code inside a method similar to:
static char data[] = "123456789";
I want to fill the above data array with a million characters not just nine.
But since it is tedious to type it, I want to do that in for loop.
Is that possible to do it keeping it as "static char data[]"?
edit:
static char data[1000000];
for(int i=0; i<1000000; i++)
{
data[i] = 1;
}
There are multiple ways to achieve this in C:
you can declare the global static array as uninitialized, write an initialization function and call this function at the beginning of the program. Unlike C++, C does not have a standard way to invoke such an initialisation function at program startup time, yet some compilers might provide an extension for this.
static char data[1000000];
void init_data(void) {
//the loop below will generate the same code as
//memset(data, 1, sizeof data);
for (int i = 0; i < 1000000; i++) {
data[i] = 1;
}
}
int main() {
init_data();
...
}
you can change your program logic so the array can be initialized to 0 instead of 1. This will remove the need for an initialization function and might simplify the code and reduce the executable size.
you can create the initializer for the array using an external program and include its output:
static char data[1000000] = {
#include "init_data.def"
};
you can initialize the array using macros
#define X10(s) s,s,s,s,s,s,s,s,s,s
#define X100(s) X10(s),X10(s),X10(s),X10(s),X10(s),X10(s),X10(s),X10(s),X10(s),X10(s)
#define X1000(s) X100(s),X100(s),X100(s),X100(s),X100(s),X100(s),X100(s),X100(s),X100(s),X100(s)
#define X10000(s) X1000(s),X1000(s),X1000(s),X1000(s),X1000(s),X1000(s),X1000(s),X1000(s),X1000(s),X1000(s)
#define X100000(s) X10000(s),X10000(s),X10000(s),X10000(s),X10000(s),X10000(s),X10000(s),X10000(s),X10000(s),X10000(s)
static char data[1000000] = {
X100000(1), X100000(1), X100000(1), X100000(1), X100000(1),
X100000(1), X100000(1), X100000(1), X100000(1), X100000(1),
};
Note however that this approach will be a stress test for both your compiler and readers of your code. Here are some timings:
clang: 1.867s
gcc: 5.575s
tcc: 0.690s
The last 2 solutions allow for data to be defined as a constant object.
Is that possible to do it keeping it as "static char data[]"?
No, you have to specify the size explicitly. If you wish to compile-time initialize the array rather than assigning to it in run-time with a for loop or memset, you can use tricks such as this.
Another option might be to use dynamic allocation with malloc instead, but then you have to assign everything in run-time.
You can define statically allocated arrays in various ways, incidentally, this has nothing to do with the static keyword, see this if you need more information about static variables. The following discussion won't have anything to do with that, hence I will be omitting your static keyword for simplicity.
An array declared as:
char data[] = "123456789";
is allocated in the stack in the compile time. Compiler can do that since the size of the array is implicitly given with the string "123456789" to be 10 characters, 9 for the data and +1 for the terminating null character.
char data[];
On the other hand, will not compile, and your compiler will complain about missing array sizes. As I said, since this declaration allocates the array in the compile time, your compiler wants to know how much to allocate.
char data[1000000];
This on the other hand will compile just fine. Since now the compiler knows how much to allocate. And you can assign elements as you did in a for loop:
for(int i=0; i<1000000; i++)
{
data[i] = 1;
}
Note:
An array of million chars has quite a respectable size, typically 1Mb, and may overflow your stack. Whether or not that it actually will depends on pretty much everything that it can depend on, but it certainly will rise some eyebrows even if your code works fine. And eventually, if you keep increasing the size you will end up overflowing your buffer.
If you have truly large arrays you need to work with, you can allocate them on the heap, i.e., in the wast empty oceans of your ram.
The part above hopefully should have answered your question. Below is simply an alternative way to assign a fixed value, such as your (1), to a char array, instead of using for loops. This is nothing but a more convenient way (and perhaps a better practice), you are free to ignore it if it causes confusion.
#include <string.h>
#define SIZE 100000
// Create the array, at this point filled with garbage.
static char data[SIZE];
int main( void )
{
// Initialise the array: assigns *integer 1* to each element.
memset( data, 1, sizeof data )
//^___ This single line is equivalent of:
// for ( int i = 0; i < SIZE; i++ )
// {
// data[i] = 1;
// }
.
.
.
return 0;
}
I'm a student learning C and I was puttering around with arrays of strings and malloc().
I have the following code that is supposed to load an array of strings (statically created) with dynamically created strings (please forgive / correct me if my terminology does not align with the code I have).
The problem is, once I go to free that memory, I get the following error: free(): invalid pointer
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#define RAM_SIZE 5
char* ram [RAM_SIZE];
int next_free_cell = 0;
void freeAndNullRam(){
for (int i = 0 ; i < RAM_SIZE ; i++){
printf("%d\n", i);
free(ram[i]);
ram[i] = NULL;
}
}
int main(int argc, const char *argv[])
{
for (int i= 0; i < RAM_SIZE; i++){
ram[i] = (char*)malloc(sizeof(char*)*5);
ram[i] = "aaaa";
}
for (int i= 0; i < RAM_SIZE; i++){
int empty = (ram[i] ==NULL);
if(!empty){
printf("%s\n", ram[i]);
}
}
freeAndNullRam();
for (int i= 0; i < RAM_SIZE; i++){
int empty = (ram[i] ==NULL);
printf("%d\n", empty);
}
return 0;
}
I know the issue is definitely in the freeAndNullRam() function (obviously), but I don't understand why. My understanding is that at compile time, an array of 5 pointers to char arrays is created, but to actually fill the cells of the array, I need to malloc them some memory. Why does the program complain when I free the pointers in the array, but not when I give them memory?
Thanks!
ram[i] = "aaaa"; reassigns the pointers at a[i] to point to static memory, discarding the result of malloc. Later on you pass those pointers to free, which fails because they were not the result of an *alloc function.
Use strcpy to instead copy the string from static memory into your allocated destination.
strcpy(a[i], "aaaa")
Here's a reworked version of your code to be more idiomatic C:
#include <stdio.h>
#include <stdlib.h>
// Create an array of arbitrary size
char* alloc_array(size_t size) {
// calloc() will give you a pre-zeroed (NULL) allocation, malloc() may not
return calloc(size, sizeof(char*));
}
// Clears out all entries in the array, leaving only NULL
void clear_array(char* array, size_t size) {
for (size_t i = 0; i < size; ++i) {
// free(NULL) doesn't do anything, and is easier than a test
free(array[i]);
array[i] = NULL;
}
}
// Clears, then frees the array
void free_array(char* array, size_t size) {
clear_array(array, size);
free(array);
}
int main(int argc, const char *argv[])
{
// Whenever possible use local variables, not global variables
size_t size = 5;
char* entries = alloc_array(size);
for (size_t i = 0; i < size; ++i) {
// Make a copy with strdup() so this can be released with free()
// later on. A string like "..." is static, it was never allocated.
entries[i] = strdup("aaaa");
}
for (size_t i = 0; i < size; i++) {
// Express conditions in the if statment directly
if (entries[i] != NULL) {
printf("%s\n", ram[i]);
}
}
clear_array(entries);
for (size_t i = 0; i < size; i++) {
printf("%d\n", entries[i] != NULL);
}
// Don't forget to release any allocated memory.
free_array(entries);
return 0;
}
There's a lot of bad habits in your original code you should work to expunge as quickly as possible so these things don't take root. In particular, global variables are a huge problem that need to be avoided.
One thing to remember is unless something was explicitly allocated with malloc() or a variant like calloc(), or was given to your code with an understanding that it was allocated in such a fashion, you should not call free() on it.
Not every pointer was allocated dynamically, and not every dynamically allocated pointer was allocated with malloc(). Some C code can be very confusing as a result of this.
C's syntax strongly suggests that "aaaa" is a "string". People even talk of this syntax that way: they call it "strings". But "aaaa" is nothing such. It's the unfortunately named string literal, which is not a string - neither in C nor in C++. A char * is not a string either - it's a pointer-typed value. It's used to represent strings, but itself is not a string - not even close.
You have quite reasonably expected that "aaaa" might behave like any other rvalue of the "obvious" type. Alas, while 1 is an integer literal of type int, "aaaa" is a string literal of a pointer type const char * - its value is not a string, but a pointer!
It's as if when you wrote 42, C gave you a const int * pointing to 42. That's what "string" literals do. That's the awfully deplorable side of C :(
In C++, there actually is a string type (std::string), and you can even write literals of that type with a new syntax introduced in C++11: "aaaa"s is an rvalue* of type std::string, and you can assign them exactly as you would expect of any other value type like int.
Since you're already thinking a bit like in C++, perhaps you can investigate that language next. It takes much less effort to do plenty of basic things in C++ compared to C.
*technically rvalue reference
Can I use strlen of a const char* in a loop like this and expect O(n) time complexity, or would it result in O(n^2)? I think it looks cleaner than using a variable for the string length.
void send_str( const char* data ) {
for (uint8_t i = 0; i < strlen(data); i++)
send_byte( data[i] );
}
Does it depend on the optimization level?
I don't think you can ever depend on an optimization happening.
Why not do it like this, if you really want to avoid an extra variable:
void send_str(const char *data)
{
for(size_t i = strlen(data); i != 0; --i)
send_byte(*data++);
}
Or, less silly, and more like an actual production-quality C program:
void send_str(const char *data)
{
while(*data != '\0')
send_byte(*data++);
}
There's no point at all in iterating over the characters twice, so don't call strlen() at all, detect the end-of-string yourself.
The compiler might optimize that, but perhaps not to the point you want it to. Obviously depending on the compiler version and the optimization level.
you might consider using the MELT probe to understand what GCC is doing with your code (e.g. what internal Gimple representation is it transformed to by the compiler). Or gcc -fverbose-asm -O -S to get the produced assembler code.
However, for your example, it is simpler to code:
void send_str(const char*data) {
for (const char*p = data; *p != 0; p++)
send_byte(*p);
}
If the definition of send_byte() is not available when this code is compiled (eg. it's in another translation unit), then this probably can't be optimised in the way you describe. This is because the const char * pointer doesn't guarantee that the object pointed to really is const, and therefore the send_byte() function could legally modify it (send_byte() may have access to that object via a global variable).
For example, were send_byte() defined like so:
int count;
char str[10];
void send_byte(char c)
{
if (c == 'X')
str[2] = 0;
count++;
}
and we called the provided send_str() function like so:
count = 0;
strcpy(str, "AXAXAX");
send_str(str);
then the result in count must be 2. If the compiler hoisted the strlen() call in send_str() out of the loop, then it would instead be 6 - so this would not be a legal transform for the compiler to make.
After about 5 years of programming in dynamic languages such as Python and JS I am starting to feel I'm missing out of what happens under the hood. Languages such as these are really great because they let you focus on what you have to do leveraging the trouble of working with pointers, memory allocation and many searching, sorting, inserting algorithms. Even though I never regret using these languages as I really feel they are ridiculously powerful I feel that, in order to become a better programmer, I need to take a step back and understand what happens under the hood!
I decided to do this by writing a simple word counter: The app gets all the params and outputs all the unique words, each one with a counter: "Hello world Hello" would return "Hello: 2", "world: 1" (not taking in consideration the actual output structure). This program is the Python equivalent of:
import sys
from collections import defaultdict
def main():
results = defaultdict(int)
for word in sys.argv[1:]:
results[word] += 1
print results
Writing it in C is a bit different, I feel like I'm getting something utterly wrong with pointers, arrays of pointers and all that stuff! I want to get better, Help me get better!!
#include <stdio.h>
#include <stdlib.h>
// This is what a key-value pair: <int, string>
typedef struct {
int counter;
unsigned char* word;
} hashmap;
// Checks if inside the array of results, hashmap->word is equals to word paramter
hashmap* get_word_from_results(hashmap* results[], int count, const char* word) {
int i;
hashmap* result;
for (i = 0; i < count; i++) {
result = results[i];
if (result->word == (unsigned char *)word)
return result;
}
return NULL;
}
int main(int argc, const char *argv[])
{
hashmap* results;
int results_counter = 0;
int i;
const char* word;
for (i = 1; i < argc; i++) {
word = argv[i];
hashmap* result = get_word_from_results(&results, results_counter, word);
// If result is NULL, means word is not inserted yet, let's create a new hashmap and insert it inside the array
if (result == NULL) {
hashmap h;
h.counter = 1;
h.word = (unsigned char *)word;
results = realloc(NULL, (results_counter + 1) * sizeof(hashmap) );
// NOTE: potential memory leak? would h be deallocated?
results[results_counter] = h;
results_counter++;
printf("NEW\n");
} else {
// The word already exists in the hashmap array, let's increase it by 1
result->counter++;
printf("INCREMENTED\n");
}
}
return 0;
}
Can anyone give me some advice? what am I doing wrong here? Are my pointers okay? also I think I spotted a memory leak (see comments), would anyone like to submit their version??
Thanks!! you guys are so cool!!
Daniel
The major pointer issue in your program is that when hashmap* results is passed to realloc for the first time, its value is uninitialized. This is undefined behavior. You should initialize the pointer to NULL, like this:
hashmap* results = NULL;
The other problem is comparing strings: you need to use strcmp rather than ==. Remember that strcmp returns zero when strings are equal.
There are also memory leaks at the end of your program. You should free results, along with the words that are stored inside its elements.
Of course the thing that you call hashmap behaves precisely like a dynamic array. Programming a hash table in C presents a different level of challenge, however, so I would encourage you to make your current approach work.
char *substring(char *text, int position, int length)
{
int i, j=0;
char *temp ;
for(i=position-1; i<position+length-1; i++)
{
temp[j++] = text[i];
}
temp[j] = '\0';
return temp;
}
Hi What is the error in the following code.. I am trying to run this on Fedora Machine.. And its giving me a run-time error "Segmentation Fault". What is this error all about.. and why is it giving this error..
Thanks..
temp is uninitialized.
You need to allocate memory for temp - currently it's just a dangling pointer. You can use malloc for this but note that the caller will need to ensure that this storage is subsequently freed.
For example:
char *substring(const char *text, int position, int length)
{
char *temp = malloc(length + 1);
int i, j;
for (i = position, j = 0; i < position + length; i++, j++)
{
temp[j] = text[i];
}
temp[j] = '\0';
return temp;
}
It means that your code has violated some restriction set up by the operating system, in this case you are writing to memory that you do not have the right to write to.
This is because your temp variable is just an uninitialized pointer, it doesn't contain the address of memory where you are allowed to write.
If you expect to write length + 1 characters, it must be pointing to at least that many bytes worth of space.
Since you expect to return the string, you need to either make it static (but that can be dangerous), or allocate the space dynamically:
if((temp = malloc(length + 1)) == NULL)
return NULL;
I am making a copy of the sub-string into another pointer, this is the just the simple way of finding one substring of a given string..
Hope i am that very simple way in the correct manner..
Also, The methods given by SysAdmin,, looks pretty complex ones, but still thanx for the suggestion.. I will try and learn those as well.. But if you can tell me whether i have implemented the very basic pattern searching algorithm correctly, then it would be very kind..
Thanks..
while the answer is obvious - i.e temp is not initialized,
here is a suggetion.
If your intention is to find a substring in another string,
few alternatives are,
1. use C strstr(...)
2. Robin-Karp method
3. Knuth-Morris-Pratt method
4. Boyer Moore method
Update:
Initialy I thought this question was related to finding the substring (based on the title).
Anyway, this looks like strchr() implementation.
It is obvious from the code that you missed to allocate / initialize the pointer *temp. It is pointing to nowhere.
You either have to use malloc or strdup and do the rest. But yeah , you may also want to explore using strncpy (null terminate) to simplify the code.