Hackerrank: C - Querying the Document - c

I'm stuck with an unidentified Segmentation Fault.
My erroneous function receives a string text. It should convert it into a document and return it. A document is made of paragraphs(separated by '\n') which is made of sentences(separated by '.') which is made of words(separated by ' '). You may refer the complete problem statement here.
Here is the relevant part of my code:
char**** get_document(char* text) {
int p = 0, s = 0, w = 0, c = 0;
char**** document;
document = malloc(sizeof(char***));
document[0] = malloc(sizeof(char**));
document[0][0] = malloc(sizeof(char*));
document[0][0][0] = malloc(sizeof(char));
while (*text)
{
if (*text == ' ')
{
c = 0;
++w;
document[p][s] = realloc(document[p][s], sizeof(char*) * (w + 1));
}
else if (*text == '.')
{
c = 0;
w = 0;
++s;
document[p] = realloc(document[p], sizeof(char**) * (s + 1));
}
else if (*text == '\n')
{
c = 0;
w = 0;
s = 0;
++p;
document = realloc(document, sizeof(char***) * (p + 1));
}
else
{
++c;
document[p][s][w] = realloc(document[p][s][w], sizeof(char) * (c + 1));
document[p][s][w][c - 1] = *text;
document[p][s][w][c] = '\0';
}
++text;
}
return document;
}
After debugging, I came to know that the program crashes when
w = 1 at document[p][s][w][c - 1] = *text;
I have no idea why this is happening. I checked the values of p, s, w, and c before the execution of that statement, and if the realloc statements were executing properly.
But in vain!
What might be going wrong in my code?

You need to allocate memory for the new paragraphs, sentences and words. By reallocation you increased the actual dimension size, but the new element was a null pointer which caused the segfault.
char**** get_document(char* text) {
int p = 0, s = 0, w = 0, c = 0;
char**** document;
document = malloc(sizeof(char***));
document[0] = malloc(sizeof(char**));
document[0][0] = malloc(sizeof(char*));
document[0][0][0] = malloc(sizeof(char));
while (*text)
{
if (*text == ' ')
{
c = 0;
++w;
document[p][s] = realloc(document[p][s], sizeof(char**) * (w + 1));
document[p][s][w] = malloc(sizeof(char*));
}
else if (*text == '.')
{
c = 0;
w = 0;
++s;
document[p] = realloc(document[p], sizeof(char**) * (s + 1));
document[p][s] = malloc(sizeof(char**));
document[p][s][w] = malloc(sizeof(char*));
}
else if (*text == '\n')
{
c = 0;
w = 0;
s = 0;
++p;
document = realloc(document, sizeof(char****) * (p + 1));
document[p] = malloc(sizeof(char***));
document[p][s] = malloc(sizeof(char**));
document[p][s][w] = malloc(sizeof(char*));
}
else
{
++c;
document[p][s][w] = realloc(document[p][s][w], sizeof(char) * (c + 1));
document[p][s][w][c - 1] = *text;
document[p][s][w][c] = '\0';
}
++text;
}
return document;
}
Moreover, your printing method in the main does not work, because you did not save the spaces (you needn't anyways). So, I fixed it:
int main()
{
char* text = "New word.No space before a sentence.\nThis is a new paragraph.";
char**** doc = get_document(text);
int p = 0, s = 0, w = 0, c = 0;
char ch;
while (ch = *text)
{
if (ch == ' ')
{
putchar(' ');
c = 0;
++w;
}
else if (ch == '.')
{
putchar('.');
c = 0;
w = 0;
++s;
}
else if (ch == '\n')
{
putchar('\n');
c = 0;
w = 0;
s = 0;
++p;
}
else putchar(doc[p][s][w][c++]);;
text++;
}
return 0;
}
The output seems correct:
New word.No space before a sentence.
This is a new paragraph.
I think you don't have to free the doc because you are returning from the main after it and Hackerrank will handle that if needed. But just note that you should take care of it otherwise.

Related

turning morse into english from a txt file in C, only iterates 1 char in the string before stopping

Using the code below it only reads one char and does not convert morse to letter. My idea was to create a string of one morse "letter" and put it in the convert function, however only 1 char is being read since I am only seeing a single 1 printed on the screen after the string itself is printed. The string only consists of '-' , '.' , ' '. I was wondering if anyone knows what the solution might be.
char convertToLetter(M* data, char word[10]) {
int size = 0;
char correct;
while (size < 60)
{
int compare = strcmp(word, data->morse);
if (compare == 0) {
correct = data->letter;
}
data++;
size++;
}
correct = '\0';
return correct;
}
int main(){
//some code here for opening a file.
char curSent[200];
char letter[6] = "";
int i = 0;
char* fullString = (char*)malloc(1000 * sizeof(char));
fullString[0] = '\0';
while (fgets(curSent, 200, inFile) != NULL) {
if (curSent[0] != '\n') {
curSent[strlen(curSent) - 1] = '\0';
strcat_s(fullString,1000, curSent);
}
else {
printf("%s", fullString);
printf("\n\n");
int j = 0;
while (i < strlen(fullString)) {
if (fullString[i] != ' ') {
fullString[i] = letter[j];
i++;
j++;
printf("%d \n", 1);
}else if (fullString[i + 1] == ' ' && fullString[i] == ' ') {
printf("%d", 2);
printf(" %c", convertToLetter(dictionary, letter));
memset(letter, 0, strlen(letter));
j = 0;
i = i + 2;
}else if (fullString[i] == ' ') {
printf("%d", 3);
printf("%c", convertToLetter(dictionary, letter));
memset(letter, 0, strlen(letter));
j = 0;
i = i++;
}
}
memset(fullString, 0, strlen(fullString));
i = 0;
}
}
//printf("%s", fullString);
getchar();
return 0;
}

my double pointer table isnt entierly returned. my function is suppose to split a string with a charset

char **ft_split(char *str, char *charset)
{
int i = 0;
int index = 0;
int len;
if (condition(str[0], charset) != 1)
while (condition(str[index], charset) != 1)
index++;
while (condition(str[index], charset) == 1)
index++;
int tab = nbword(str, charset);
printf("%d, len\n\n", tab);
char **tableau = malloc((tab + 1) * sizeof(char));
while (str[index] != '\0')
{
while (condition(str[index], charset) == 1)
index++;
len = wordlen(str, index, charset);
tableau[i++] = malloc(len + 1 * sizeof(char));
ft_strSPcpy(tableau[i - 1], str, len - 1, index);
printf("tableau[%d] = %s\n", i - 1, tableau[i - 1]);
index += len;
}
tableau[i] = 0;
return tableau;
free(tableau);
}
this is where something blocks.
before main
tableau[0] = bodeg
tableau[1] = c vr
tableau[2] = iment
tableau[3] = uper
in function main
tableau[0] = tableau[last] = (null)
c vr
iment
uper
and this is what i get when executed.
so as you can see, in the main function, the first string is empty?? what happenned ?
i also tried to see after my last while, all strings were good.
thank you

Segmentation fault in HackerRank C program

This is the challenge I'm trying to solve:
https://www.hackerrank.com/challenges/querying-the-document/
So far I have made progress but I am stuck at a Segmentation Fault and I can't figure out why.
The following is an abridged version of the whole source code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char**** get_document(char* text) {
int spaces = 0, periods = 0, newlines = 0;
for(int i = 0; i != strlen(text); i++) {
if(text[i] == ' ')
spaces++;
else if(text[i] == '.')
periods++;
else if(text[i] == '\n')
newlines++;
}
char** para[periods + 1]; // each paragraph stores that many sentences
char* senten[spaces + 1]; // each sentence stores that many words
char*** doc[newlines + 1]; // each document stores that many paragraphs
int start = 0, k = 0, m, p = 0, x = 0;
for(int i = 0; i != strlen(text); i++) {
if(text[i] == ' ' || text[i] == '.') { // space or period means there was a word before it
senten[k] = (char*) malloc(sizeof(char) * (i - start)); // store each word
m = 0;
for(int j = start; j < i; )
senten[k][m++] = text[j++];
senten[k][m++] = '\0'; // append a '\0' to end the string
if(text[i + 1] == '\n') { // newline means that a new paragraph is starting
para[p] = senten; // store pointer to sentence in para
while(k)
senten[k--] = NULL; // don't need now
start = i + 2;
p++;
}
else
start = i + 1;
k++;
}
if(i == strlen(text) - 1) { // end of file
doc[x++] = para; // store pointer to paragraph in doc
while(p)
para[p--] = NULL; // don't need
}
}
return doc;
}
int main()
{
char* text = "Hello World.\nHi.Bye.";
char**** doc = get_document(text);
printf("%s",doc[0][0][0]); // should print "Hello"
return 0;
}
In short the program is supposed to take a char* and output a char****.
Example:
If char * text = "Hello World.\nHi.Bye.";
Then char **** doc = {{{"Hello","World"}},{{"Hi"},{"Bye"}}};
You return the local variable in get_document function:
char** para[periods + 1]; // each paragraph stores that many sentences
char* senten[spaces + 1];
char*** doc[newlines + 1];
...
return doc;
It's bad idea, Because out of get_document function, the variable doc maybe does not exist.
You should use:
char*** para = malloc((periods + 1) * sizeof(char **));
char** senten = malloc((spaces + 1) * sizeof(char *));
char**** doc = malloc((newlines + 1)*sizeof(char ***));
This is how I modified my code. Now it passes all the test cases.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
char**** get_document(char* newtext) {
int spaces = 0, periods = 0, newlines = 0;
for(int i = 0; i != strlen(newtext); i++) {
if(newtext[i] == ' ')
spaces++;
else if(newtext[i] == '.')
periods++;
else if(newtext[i] == '\n')
newlines++;
}
char*** para = malloc((periods + 1) * sizeof(char **));
char** senten = malloc((spaces + 1) * sizeof(char *));
char**** doc = malloc((newlines + 1) * sizeof(char ***));
int start = 0, k = 0, m, p = 0, x = 0, f = 0, pp = 0;
int pcount = 0;
for(int i = 0; i != strlen(newtext); i++) {
if(newtext[i] == '.') pcount++;
if(newtext[i] == ' ' || newtext[i] == '.') { // space or period means there was a word before it
senten[k] = (char*) malloc(sizeof(char) * (i - start) + 1); // store each word
m = 0;
for(int j = start; j < i; )
senten[k][m++] = newtext[j++];
senten[k][m++] = '\0'; // append a '\0' to end the string
k++;
if(i != strlen(newtext) && newtext[i + 1] == '\n') // newline means that a new paragraph is starting
start = i + 2;
else
start = i + 1;
if(i != strlen(newtext) && isalpha(newtext[i + 1]) && newtext[i] == '.') {
para[p++] = senten;
senten = malloc((spaces + 1) * sizeof(char *));
k = 0;
}
if((i != strlen(newtext) && newtext[i + 1] == '\n') || i + 1 == strlen(newtext)) {
para[p++] = senten;
senten = malloc((spaces + 1) * sizeof(char *));
k = 0;
doc[f++] = &(para[pp]);
pp += pcount;
pcount = 0;
}
}
}
return doc;
}
int main()
{
char* newtext = "Hello World.\nHi.Bye.\nWow.";
char**** doc = get_document(newtext);
printf("%s\n", doc[0][0][0]);
printf("%s\n", doc[0][0][1]);
printf("%s\n", doc[1][0][0]);
printf("%s\n", doc[1][1][0]);
printf("%s\n", doc[2][0][0]);
return 0;
}

C split string function returns \377 at the end of string instead of \0. Why?

I tried to implement a small splitStringByString() function in C, this is how I have come so far:
char* splitStringByString(char* string, char* delimiter){
int i = 0, j = 0, k = 0;
while(*(string + i) != '\0'){
j = i;
while((*(string + j) == *(delimiter + k)) && (*(string + j) != '\0')){
if(*(delimiter + k + 1) == '\0'){
// return string from here.
char result[(strlen(string) - strlen(delimiter) + 1)]; // + 1 for '\0'
i = 0;
j++;
while(*(string + j) != '\0'){
result[i] = *(string + j);
i += 1;
j++;
}
i = (int)strlen(result);
result[i - 1] = '\0';
return result;
}
k++;
j++;
}
i++;
}
return NULL;
}
So it works more or less;
the function returns the string after the delimiter as wanted, but at the end of this string (the last character) is always \377.
I already found something that said this is an octal number or so (stackoverflow), but it is not very clear for me. Could you help me and give me some advice about what I did wrong?
Thanks a lot! :-)
I do not understand your code but to do what you mention in the comment
char *splitSstring(char *haystack, char *separator)
{
char *result = (haystack == NULL || separator == NULL || !strlen(haystack) || !strlen(separator)) ? NULL : haystack;
if (result != NULL)
{
result = strstr(haystack, separator);
if (result != NULL) result += strlen(separator);
}
return result;
}
or if you want to have it in the separate string
char *splitSstring(char *haystack, char *separator, char *res)
{
char *result = (haystack == NULL || separator == NULL || !strlen(haystack) || !strlen(separator)) ? NULL : haystack;
if (result != NULL)
{
result = strstr(haystack, separator);
if (result != NULL)
{
result = result + strlen(separator);
if(res == NULL) res = malloc(strlen(result) + 1);
if(res != NULL) strcpy(res, result);
result = res;
}
}
return result;
}
you can provide your own buffer to the function or if you pass NULL it will be allocated for you. But you need to remember to free it;

Given two strings, find the words that are common to both the strings

Eg: input: char *str1 = "the are all is well";
char *str2 = "is who the";
output: common words in two given strings, return 2D array of strings.
#define SIZE 31
char ** commonWords(char *str1, char *str2) {
int i,j=0,count1,count2,k=0,a,b,m=0,n;
char str3[100][100], str4[100][100];
char **output;
output = (char **)malloc(SIZE*sizeof(char*));
if (str1 == NULL || str2 == NULL)
{
return NULL;
}
for (i = 0; str1[i] != '\0'; i++)
{
if (str1[i] != ' ')
{
str3[j][k++] = str1[i];
}
else
{
str3[j][k++] = '\0';
j++;
k = 0;
}
}
str3[j][k++] = '\0';
count1 = j > 0 ? j + 1 : j;
j = k = 0;
for (i = 0; str2[i] != '\0'; i++)
{
if (str2[i] != ' ')
{
str4[j][k++] = str2[i];
}
else
{
str4[j][k++] = '\0';
j++;
k = 0;
}
}
str4[j][k++] = '\0';
count2 = j > 0 ? j + 1 : j;
for (i = 0; i < count1; i++)
{
for (j = 0; j < count2; j++)
{
if (str3[i][k] == str4[j][k])
{
if (str3[i][k + 1] == str4[j][k + 1] && str3[i][k + 2] == str4[j][k + 2] == '\0')
{
a = i;
b = k;
while (str3[a][b] != '\0')
{
output = (char **)malloc(SIZE*sizeof(char));
output[m][n] = str3[a][b];
n++;
b++;
}
output[m][n] = '\0';
}
else if (str3[i][k + 1] == str4[j][k + 1] && str3[i][k + 2] == str4[j][k + 2])
{
a = i;
b = k;
while (str3[a][b] != '\0')
{
output = (char **)malloc(SIZE*sizeof(char));
output[m][n] = str3[a][b];
n++;
b++;
}
output[m][n] = '\0';
m++;
}
}
}
}
return output;
}
I am debugging this code in visual studios and the test is failed.Its showing this " message: Exception code: C0000005" .It means error related to memory space allocation.So where did i go wrong?
You have the statement
output = (char **)malloc(SIZE*sizeof(char));
at two lines of your program.
You have to modify this statement in order allocate memory for the double pointer output of type char**, but you also need to allocate memory for every element of output like this :
int i;
output = (char **)malloc(SIZE*sizeof(char*));
for (i = 0; i < SIZE; i++)
output[i] = (char *)malloc(x*sizeof(char));
where x is the desired size.
Also check for NULL pointer return, for instance
if (output[i] == NULL)
....

Resources