My function save_words receives armazena and size. Armazena is a dynamic array which contains paragraphs, and size it's the size of the array. In this function i want to put word to word in other dynamic array called words. When i run it, it crashes.
I appreciate your help.
char **save_words(char **armazena, int *size)
{
char *token = NULL;
char** armazena_aux = armazena;
int i, count=0;
char **words = (char**) malloc(sizeof(char*)*(10));
for(i=0; i<size; i++)
{
token = strtok(*(armazena+i)," .?!,");
while( token != NULL )
{
int tam = strlen(token);
armazena[count] = (char*) malloc(tam+2);
strcpy(armazena[count],token);
armazena[count][tam+1]='\0';
count++;
token = strtok(NULL, " .?!,");
if (count%10==0)
{
words = realloc(words, sizeof(char*)*(count + 10));
}
}
}
return words;
}
Is armazena[count] = (char*) malloc(tam+2); what you want? I would have thought words[count] = ...;. The first time through the outer loop is ok, because you hoist armazena[0] into strtok, but if it contains more than one word, your second time through the outer loop will be processing strings generated from the first time.
Worse, if that first string contained more words than the armazena vector can accommodate, you will be corrupting something...
Related
I am trying to break up the sentence "once upon a time" into an array of words. I am doing this via a for loop, detecting three conditions:
It's the end of the loop (add the \0 and break);
It's the separator character (add the \0 and advance to the next word)
It's anything else (add the character)
Here is what I have now:
#include <stdlib.h>
#include <stdio.h>
char ** split_string(char * string, char sep) {
// Allow single separators only for now
// get length of the split string array
int i, c, array_length = 0;
for (int i=0; (c=string[i]) != 0; i++)
if (c == sep) array_length ++;
// allocate the array
char ** array_of_words = malloc(array_length + 1);
char word[100];
for (int i=0, char_num=0, word_num=0;; i++) {
c = string[i];
// if a newline add the word and break
if (c == '\0') {
word[char_num] = '\0';
array_of_words[word_num] = word;
break;
}
// if the separator, add a NUL, increment the word_num, and reset the character counter
if (c == sep) {
word[char_num] = '\0';
array_of_words[word_num] = word;
word_num ++;
char_num = 0;
}
// otherwise, just add the character in the string and increment the character counter
else {
word[char_num] = c;
char_num ++;
}
}
return array_of_words;
}
int main(int argc, char *argv[]) {
char * input_string = "Once upon a time";
// separate the string into a list of tokens separated by the separator
char ** array_of_words;
array_of_words = split_string(input_string, ' ');
printf("The array of words is: ");
// how to get the size of this array? sizeof(array_of_words) / sizeof(array_of_words[0]) gives 1?!
for (int i=0; i < 4 ;i++)
printf("%s[sep]%d", array_of_words[i], i);
return 0;
}
However, instead of printing "once", "upon", "a", "time" at the end, it's printing "time", "time", "time", "time".
Where is the mistake in my code that is causing this?
Here is a working example of the code: https://onlinegdb.com/S1ss6a4Ur
You need to allocate memory for each word, not just for one. char word[100]; only puts aside memory for one word, and once it goes out of scope, the memory is invalid. Instead, you could allocate the memory dynamically:
char* word = malloc(100);
And then, when you found a separator, allocate memory for a new word:
if (c == sep) {
word[char_num] = '\0';
array_of_words[word_num] = word;
word = malloc(100);
Also, this here is incorrect:
char ** array_of_words = malloc(array_length + 1);
You want enough memory for all the char pointers, but you only allocate 1 byte per pointer. Instead, do this:
char ** array_of_words = malloc(sizeof(char*)*(array_length + 1));
The sizeof(array_of_words) / sizeof(array_of_words[0]) works to calculate the amount of elements when array_of_words is an array, because then its size is known at compile time (barring VLAs). It's just a pointer though, so it doesn't work as sizeof(array_of_words) will give you the pointer size. Instead, you'll have to calculate the size on your own. You already do so in the split_string function, so you just need to get that array_of_words out to the main function. There are multiple ways of doing this:
Have it be a global variable
Pass an int* to the function via which you can write the value to a variable in main (this is sometimes called an "out parameter")
Return it along with the other pointer you're returning by wrapping them up in a struct
Don't pass it at all and recalculate it
The global variable solution is the most simple for this small program, just put the int array_length = 0; before the split_string instead of having it inside it.
Last but not least, since we used malloc to allocate memory, we should free it:
for (int i = 0; i < array_length; i++) {
printf("%s[sep]%d", array_of_words[i], i);
free(array_of_words[i]); // free each word
}
free(array_of_words); // free the array holding the pointers to the words
Is strtok not suitable?
char str[] = "once upon a time";
const char delim[] = " ";
char* word = strtok(str, delim);
while(word != NULL)
{
printf("%s\n", word);
word = strtok(NULL, delim);
}
I am required to write a function that splits a string into individual words.
My first parameter is a string. We assume that the words in the string are separated by single spaces, with no spaces before the first word or after the second word. Punctuation like spaces for example is part of a word. My second parameter is an address of an integer in which the function gives it the value of the number of words in the string. The return value is a pointer that points of an array of strings containing the individual words in the sentence. I need to allocate it memory from the heap and have one word in each index of the array. The strings are copies of the original words, not pointers. Here is my code :
char** splitString(char theString[], int *arraySize) {
*arraySize = countSpaces(theString) + 1; //Points to the number of words in the string.
char** pointerToArrayOfStrings = malloc(*arraySize * sizeof(char *)); //Allocated memory for '*arraySize' character pointers
int characters = 0;
for (int i = 0; i < *arraySize; i++) {
while (theString[characters] != ' ' || theString[characters] != '\0') {
characters++;
}
characters++;
pointerToArrayOfStrings[i] = (char *)malloc(characters);
pointerToArrayOfStrings[i][characters] = '\0';
}
for (int word = 0; word < *arraySize; word++) {
int ch = 0;
while (ch < strlen(pointerToArrayOfStrings[word])) {
pointerToArrayOfStrings[word][ch] = theString[ch];
}
ch+=2;
}
return pointerToArrayOfStrings;
}
This is immediately giving me segmentation faults. I am very new to pointers, so my method is to first allocate the array with the amount of memory for "numberOfWords" character pointers. Then I allocated each character pointer with the size of the corresponding word. After, I filled the slots with the characters from the original string. I don't know what I'm missing.
The comments have already addressed your questions about seg-faults etc. But since you did not say it was required how you split the string, I wanted to suggest looking at another approach.
Consider these steps:
1) Walk through string counting occurrences of white space (words) and track longest word found.
2) Knowing count, and longest word, you have what you need to allocate memory. Do it.
3) In a for loop, use strtok() with the delimiters of: , \n, \t etc. to tokenize the string.
4) Using strcpy() (also in the loop) to transfer each token into the string array.
5) Return array. Use array. Free all allocated memory.
Example code to do these steps:
char** splitString(const char theString[], int *arraySize);
char ** create_str_array(int strings, int longest) ;
int main(void)
{
int size;
char ** string = splitString("here is a string", &size);
return 0;
}
char** splitString(const char theString[], int *arraySize)
{
*arraySize = strlen(theString) + 1; //Points to the number of words in the string.
char *tok;
char *dup = strdup(theString);//create copy of const char argument
char** pointerToArrayOfStrings = NULL;
int characters = 0;
int len = 0, lenKeep = 0, wordCount = 0, i;
/// get count of words and longsest string
for(i=0;i<*arraySize;i++)
{
if((!isspace(theString[i]) && (theString[i])))
{
len++;
if(lenKeep < len)
{
lenKeep = len;
}
}
else
{
wordCount++;
len = 0;
}
}
/// create memory. (array of strings to hold sub-strings)
pointerToArrayOfStrings = create_str_array(wordCount, lenKeep);
if(pointerToArrayOfStrings)// only if memory creation successful, continue
{
/// parse original string into sub-strings
i = 0;
tok = strtok(dup, " \n\t");
if(tok)
{
strcpy(pointerToArrayOfStrings[i], tok);
tok = strtok(NULL, " \n\t");
while(tok)
{
i++;
strcpy(pointerToArrayOfStrings[i], tok);
tok = strtok(NULL, " \n\t");
}
}
}
/// return array of strings
return pointerToArrayOfStrings;
}
char ** create_str_array(int strings, int longest)
{
int i;
char ** a = calloc(strings, sizeof(char *));
for(i=0;i<strings;i++)
{
a[i] = calloc(longest+1, 1);
}
return a;
}
I am currently having difficulty reading words separated by spaces line by line from stdin. I am trying to read words line by line, and just print them, from accessing an array of strings.
If I am trying to read this sentence:
Enter words:
Hi there, how was your day sir?
Then I just want to print the sentence underneath, like this:
Your sentence:
Hi there, how was your day sir?
This is what my code is so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int
main(int argc, char *argv[]) {
char *word = NULL;
char **words = NULL;
int word_size = 1, word_len = 0, word_count = 0;
int words_size = 1, i, ch;
word = (char*)malloc(word_size *sizeof(char));
words = (char **) malloc(words_size*sizeof(char*));
printf("Enter words:\n");
while ((ch = getchar()) != EOF) {
if (isalpha(ch)) {
word_size++;
word = realloc(word, word_size+1);
word[word_len++] = ch;
word[word_len] = '\0';
}
if (isspace(ch)) {
words_size++;
words = realloc(words, words_size+1);
words[word_count] = malloc(strlen(word)+1);
words[word_count++] = word;
word_len = 0;
word_size = 1;
}
if (ch == '\n') {
printf("Your sentence is:\n");
for (i = 0; i < word_count; i++) {
printf("%s ", words[i]);
}
printf("\n");
word_len = 0;
word_size = 1;
words_size = 1;
}
}
return 0;
}
I am just not sure why this doesn't work, and why it prints the last word. I know there is a lot of mallocing and reallocing, I am just trying to get better at using them.
Any help would be appreciated
You are failing assigning the word to your char **.
Using
words[word_count++] = word;
You are assigning address of local variable word to pointer words[word_count]
That gave you, at the end of computation, all words with last stored word into word c-string.
You prepare space for the word c-string using
words[word_count] = malloc(strlen(word)+1);
So what you have to do is to copy the content of word c-string into allocaded space
strcpy(words[word_count++], word);
Otherwise you are leaking memory allocated for the word.
Side notes:
malloc and realloc can fail, so check its return value != NULL
You must free mallocated memory. On "hi-level" OS memory is freed automatically at the end of execution, but is not granted on all platforms/OS
EDIT
Another problem is that you are reallocating the wrong size for your char**
You shoud use
words_size++;
words = realloc(words, sizeof(*words)*words_size);
That is size of char * for the new number of words to store
You can also avoid to use strlen, you have the length of word stored into word_len variable
words[word_count] = malloc(word_len+1);
Last thing, before to store a new word you should check that at least alpha char was found. This avoid the output of first space char of your test sting:
if ((isspace(ch)) && (word_size>1))
I am working on a project where I am trying to read in a CSV file and check it for all sorts of different parameters. C is a new language for me so I am still getting used to it, and my code may not be as streamlined as it could be. Anyways, my issue is this: when I read the file to make sure each row has the same number of entries it works fine, but when I try to put the values into a 2D array everything gets messed up. The value at arr[0][0] should be the first value in the CSV file, but when I print out to see what it is, it is always the first value in the last row. I can't for the life of me figure this out, and I have been looking at this code and tinkering with it for hours. Any help would be much appreciated!
int parseFile(int width, int height, char*fileName) {
char*** matrix = malloc(width*height*sizeof(char*));
int counter = 0;
int pointer = 0;
FILE *file = fopen(fileName, "r");
const size_t line_size = 1024;
char* line = (char*) malloc(line_size);
while (fgets(line, line_size, file) != NULL) {
char** data = malloc(width*sizeof(char*));
char *delim = ",";
char *string = strtok(line, delim);
while (string != NULL) {
size_t ln = strlen(string) - 1;
if (string[ln] == '\n') {
string[ln] = '\0';
}
data[counter] = string;
string = strtok(NULL, delim);
counter++;
}
matrix[pointer] = data;
counter = 0;
pointer++;
}
printf("%s", matrix[0][0]);
return 0;
}
This looks nearly right, but what is happening is strtok is returning a pointer into line. That means it only has copies of the last line.
Consider creating a new memory slot for each line, or strdup the result from strtok
My code
void splitStr(char *str,char *strArray[]){
int i=0;
char *token;
const char s[2] = " ";
/* get the first token */
token = strtok(str, s);
/* walk through other tokens */
while( token != NULL )
{
strArray[i]=token;
token = strtok(NULL, s);
i++;
}
strArray[i]=NULL;
}
void addWord(char *strArray[],char *word){
int i;
char *token;
const char s[2] = " ";
token = strtok(word,s);
for(i = 0; strArray[i]!=NULL; i++) {
strcat(strArray[i],token);
}
for(i = 0; strArray[i]!=NULL; ++i) {
printf("%s\n",*(strArray+i));
}
}
int main(int argc, char *argv[]) {
char str[200],word[100],*spldWords[20];
int i;
printf("Enter sentence or string\n");
gets(str);
splitStr(str,spldWords);
for(i = 0; spldWords[i]!=NULL; ++i) {
printf("%s\n", spldWords[i]);
}
printf("\nEnter word\n");
gets(word);
addWord(spldWords,word);
return 0;
}
Output for above code:
Enter sentence or string
C programming is fun
C
programming
is
fun
Enter word
add
Caddadd
ddadd
isaddadd
ddadd
I need output is like this
Cadd
programmingadd
isadd
funadd
I'm struggling to solve this program. please anybody help me.Thanks
You're not allocating any strings for spldWords.
You declare it as an array of char*s of size 20.
And then you assign to it as though those strings have been allocated in splitStr.
You need to dynamically allocate those strings before you write to them.
EDIT:
In your splitStr loop you try to assign a string like this: strArray[i]=token; That will only assign a pointer to a location that is hopefully being maintained by strtok. You need to allocate space for a string and then copy over the characters pointed at by token to your newly allocated string:
strArray[i] = malloc(sizeof(char) * 200);
strcpy(strArray[i], token);
Anything dynamically allocated like this will need to be freed before you end your program. So, we need to know which elements of spldWords have been allocated. To do this we'll need to initialize everything in it to NULL and only free non-NULL array elements. So where you previously initialized like this: char* spldWords[20]; you now need to initialize like this:
char* spldWords[20] = {};
Finally you need to free each dynamically allocated element as soon as you're through with spldWords. Do that like this:
for(i = 0; i < sizeof(spldWords) && spldWords[i] != NULL; ++i){
free(spldWords[i]);
}
I've put all this into ideone.com for you to look at if need be: http://ideone.com/2yYoPp