I'm trying to reverse a sentence, without changing the order of words,
For example: "Hello World" => "olleH dlroW"
Here is my code:
#include <stdio.h>
#include <string.h>
char * reverseWords(const char *text);
char * reverseWord(char *word);
int main () {
char *text = "Hello World";
char *result = reverseWords(text);
char *expected_result = "olleH dlroW";
printf("%s == %s\n", result, expected_result);
printf("%d\n", strcmp(result, expected_result));
return 0;
}
char *
reverseWords (const char *text) {
// This function takes a string and reverses it words.
int i, j;
size_t len = strlen(text);
size_t text_size = len * sizeof(char);
// output containst the output or the result
char *output;
// temp_word is a temporary variable,
// it contains each word and it will be
// empty after each space.
char *temp_word;
// temp_char is a temporary variable,
// it contains the current character
// within the for loop below.
char temp_char;
// allocating memory for output.
output = (char *) malloc (text_size + 1);
for(i = 0; i < len; i++) {
// if the text[i] is space, just append it
if (text[i] == ' ') {
output[i] = ' ';
}
// if the text[i] is NULL, just get out of the loop
if (text[i] == '\0') {
break;
}
// allocate memory for the temp_word
temp_word = (char *) malloc (text_size + 1);
// set j to 0, so we can iterate only on the word
j = 0;
// while text[i + j] is not space or NULL, continue the loop
while((text[i + j] != ' ') && (text[i + j] != '\0')) {
// assign and cast test[i+j] to temp_char as a character,
// (it reads it as string by default)
temp_char = (char) text[i+j];
// concat temp_char to the temp_word
strcat(temp_word, &temp_char); // <= PROBLEM
// add one to j
j++;
}
// after the loop, concat the reversed version
// of the word to the output
strcat(output, reverseWord(temp_word));
// if text[i+j] is space, concat space to the output
if (text[i+j] == ' ')
strcat(output, " ");
// free the memory allocated for the temp_word
free(temp_word);
// add j to i, so u can skip
// the character that already read.
i += j;
}
return output;
}
char *
reverseWord (char *word) {
int i, j;
size_t len = strlen(word);
char *output;
output = (char *) malloc (len + 1);
j = 0;
for(i = (len - 1); i >= 0; i--) {
output[j++] = word[i];
}
return output;
}
The problem is the line I marked with <= PROBLEM, On the first word which in this case is "Hello", it does everything just fine.
On the second word which in this case is "World", It adds junky characters to the temp_word,
I checked it with gdb, temp_char doesn't contain the junk, but when strcat runs, the latest character appended to the temp_word would be something like W\006,
It appends \006 to all of the characters within the second word,
The output that I see on the terminal is fine, but printing out strcmp and comparting the result with expected_result returns -94.
What can be the problem?
What's the \006 character?
Why strcat adds it?
How can I prevent this behavior?
strcat() expects addresses of the 1st character of "C"-strings, which in fact are char-arrays with at least one element being equal to '\0'.
Neither the memory temp_word points to nor the memory &temp_char points to meet such requirements.
Due to this the infamous undefined behaviour is invoked, anything can happen from then on.
A possible fix would be to change
temp_word = (char *) malloc (text_size + 1);
to become
temp_word = malloc (text_size + 1); /* Not the issue but the cast is
just useless in C. */
temp_word[0] = '\0';
and this
strcat(temp_word, &temp_char);
to become
strcat(temp_word, (char[2]){temp_char});
There might be other issues with the rest of the code.
The root cause of junk characters is you use wrong input for the 2nd argument of strcat function. see explain below:
At the beginning of your function you declare:
int i, j;
size_t len = strlen(text);
size_t text_size = len * sizeof(char);
// output containst the output or the result
char *output;
// temp_word is a temporary variable,
// it contains each word and it will be
// empty after each space.
char *temp_word;
// temp_char is a temporary variable,
// it contains the current character
// within the for loop below.
char temp_char;
you can print variable's addresses in stack, they will be something like this:
printf("&temp_char=%p,&temp_word=%p,&output=%p,&text_size=%p\n", &temp_char, &temp_word,&output,&text_size);
result:
&temp_char=0x7ffeea172a9f,&temp_word=0x7ffeea172aa0,&output=0x7ffeea172aa8,&text_size=0x7ffeea172ab0
As you can see, &temp_char(0x7ffeea172a9f) is at the bottom of the stack, next 1 byte is &temp_word(0x7ffeea172aa0), next 8 bytes is &output(0x7ffeea172aa8), and so on(I used 64bit OS, so it takes 8 bytes for a pointer)
// concat temp_char to the temp_word
strcat(temp_word, &temp_char); // <= PROBLEM
refer strcat description here: http://www.cplusplus.com/reference/cstring/strcat/
the strcat second argument = &temp_char = 0x7ffeea172a9f. strcat considers that &temp_char(0x7ffeea172a9f) is the starting point of the source string, instead of adding only one char as you expect it will append to temp_word all characters starting from &temp_char(0x7ffeea172a9f) , until it meets terminating null character
The function strcat deals with strings.
In this code snippet
// assign and cast test[i+j] to temp_char as a character,
// (it reads it as string by default)
temp_char = (char) text[i+j];
// concat temp_char to the temp_word
strcat(temp_word, &temp_char); // <= PROBLEM
neither the pointer temp_word nor the pointer &temp_char points to a string.
Moreover array output is not appended with the terminating-zero character for example when the source string consists from blanks.
In any case your approach is too complicated and has many redundant code as for example the condition in the for loop and the condition in the if statement that duplicate each other.
for(i = 0; i < len; i++) {
//…
// if the text[i] is NULL, just get out of the loop
if (text[i] == '\0') {
break;
}
The function can be written simpler as it is shown in the demonstrative program below.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
char * reverse_words( const char *s )
{
char *result = malloc( strlen( s ) + 1 );
if ( result != NULL )
{
char *p = result;
while ( *s != '\0' )
{
while ( isblank( ( unsigned char )*s ) )
{
*p++ = *s++;
}
const char *q = s;
while ( !isblank( ( unsigned char )*q ) && *q != '\0' ) ++q;
for ( const char *tmp = q; tmp != s; )
{
*p++ = *--tmp;
}
s = q;
}
*p = '\0';
}
return result;
}
int main(void)
{
const char *s = "Hello World";
char *result = reverse_words( s );
puts( s );
puts( result );
free( result );
return 0;
}
The program output is
Hello World
olleH dlroW
Related
The task is:
Write a full program that takes an int n > 0 and recursively prints all combinations of characters 'a' and 'b' on the screen.
Example for n=3: aaa, baa, bba, aba, bab, aab, abb, bbb.
I assume I have to use something similar to Backtracking.
This is what I have, but Im not able to think of the rest.
void rep(int n, char str, int pos) { //n would be the length and str would be the pointer
char c[n + 1];
char d[3];
d[0] = 'a';
d[1] = 'b';
for (int j = 0; j < 2; j++) {
if (strlen(c) == n) { // if c is n long recursion ends
printf("%s", c);
} else {
c[pos] = d[j]; // put 'a' or 'b' in c[pos]
rep(n, c, pos + 1); // update pos to next position
}
}
}
The variable length array c is not initialized
char c[n+1]
Thus the call of strlen in this if statement
if(strlen(c) == n){
invokes undefined behavior.
Moreover the parameter str is not used within the function.
I can suggest the following solution as it is shown in the demonstration program below
#include <stdio.h>
#include <string.h>
void rep( char *s )
{
puts( s );
char *p = strchr( s, 'a' );
if (p != NULL)
{
memset( s, 'a', p - s );
*p = 'b';
rep( s );
}
}
int main()
{
char s[] = "aaa";
rep( s );
}
The program output is
aaa
baa
aba
bba
aab
bab
abb
bbb
That is the function rep is initially called with an array that contains a string of the required size n (in the demonstration program n is equal to 3) consisting of all characters equal to the character 'a' and recursively outputs all combinations until the string contains all characters equal to the character 'b'.
There a some issues in your code:
the str argument should have type char *
you so not need new arrays in the recursive function, but use the one the str argument points to.
you do not set a null terminator at the end of your char arrays.
instead of strlen(), use pos to determine if the recursion should stop.
Here is a modified version
#include <stdio.h>
// n is the length and str points to an array of length n+1
void rep(int n, char *str, int pos) {
if (pos >= n) {
str[n] = '\0'; // set the null terminator
printf("%s\n", str);
} else {
str[pos] = 'a';
rep(n, str, pos + 1);
str[pos] = 'b';
rep(n, str, pos + 1);
}
}
#define LEN 3
int main() {
char array[LEN + 1];
rep(LEN, array, 0);
return 0;
}
I am trying to implement this simple encryption method for a a list of numbers, the encryption is like this:
we add the 1st element of the list before every element of the entire list of numbers,
if we have:
char array = "356307042441013"
the first number is 3, that means we need to add it before every element of the list of numbers:
'33 35 36 33 30 37 30 34 32 34 34 31 30 31 33'
char result= "333536333037303432343431303133"
is there any function in C that will make the implementation easier ? because I tried doing it with shifting but couldn't get that result.
You can do following:
Step I: Allocate memory of double the size of input and + 1 to accommodate the null character to the result string.
Step II: Iterate through the input string and, in every iteration, first copy the input[0] character to current location of result string and, in very next location of result string, copy the current processing character of input string.
Step III: Once the loop exits, add null character at the end of result string.
[Take special care of empty string because it will have nothing to encrypt]
Implementation:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * encryption (const char * input) {
if ((!input) || (*input == '\0')) {
return NULL;
}
size_t len = strlen (input);
char * temp = malloc ((len * 2) + 1);
if (!temp) {
printf ("Failed to allocate memory\n");
exit (EXIT_FAILURE);
}
size_t i = 0, j = 0;
for (; input[j]; ++j) {
temp[i++] = input[0];
temp[i++] = input[j];
}
temp[i] = '\0';
return temp;
}
int main (void) {
char array[] = "356307042441013";
char * result = encryption (array);
if (result) {
printf ("result : %s\n", result);
// Free the dynamically allocated memory once done with it
free (result);
}
return 0;
}
Output:
# ./a.out
result : 333536333037303432343431303133
A cleaner, more concise solution:
#include <stdio.h>
#include <string.h>
int main()
{
char foo[] = "356307042441013";
char bar[2 * sizeof(foo) - 1];
char *src = foo, *dest = bar;
while (*src) {
*dest++ = foo[0];
*dest++ = *src++;
}
*dest = *src;
printf("foo=%s\n",foo);
printf("bar=%s\n",bar);
return 0;
}
It is better to use foo[] rather than hard-coding the length, because what if you want to change the string. If you use [] (empty brackets) the compiler will allocate exactly how many bytes you need (including the terminating null). Similarly, for bar we base the size on the size of foo by doubling it and subtracting 1 (since the terminating null does not need to be doubled).
I found a way to solve this:
int main() {
char foo[16] = "356307042441013";
char bar[2*16-1];
for (int i = 0; i < 16; i++) {
bar[2*i] = foo[i];
if (i != 16 - 1)
bar[2*i + 1] = foo[0];
}
char res[32]= "3";
strcat(res,bar);
res[30] = '\0';
printf("bar=%s\r\n",bar);
printf("begin=%s\r\n",res);
return 0;
}
I am supposed to create a program, which creates an array with the abbreviation of an constant char Array. While my program does not return any errors, it also does not print any characters at my certain printf spots. Because of that I assume that my program does not work properly, and it isn't filling my array with any characters.
void abbrev(const char s[], char a[], size_t size) {
int i = 0;
while (*s != '\0') {
printf('%c', *s);
if (*s != ' ' && *s - 1 == ' ') {
a[i] = *s;
i++;
printf('%c', a[i]);
}
s++;
}
}
void main() {
char jordan1[60] = " Electronic Frontier Foundation ";
char a[5];
size_t size = 5;
abbrev(jordan1, a, size);
system("PAUSE");
}
The actual result is nothing. At least I assume so, since my console isn't showing anything. The result should be "EFF" and the size_t size is supposed to limit my char array a, in case the abbreviation is too long. So it should only implement the letters until my array is full and then the '\0', but I did not implement it yet, since my program is apparantly not filling the array at all.
#include <stdio.h>
#include <ctype.h>
/* in: the string to abbreviate
out: output abbreviation. Function assumes there's enough room */
void abbrev(const char in[], char out[])
{
const char *p;
int zbPosOut = 0; /* current zero-based position within the `out` array */
for (p = in; *p; ++p) { /* iterate through `in` until we see a zero terminator */
/* if the letter is uppercase
OR if (the letter is alphabetic AND we are not at the zero
position AND the previous char. is a space character) OR if the
letter is lowercase and it is the first char. of the array... */
if (isupper(*p) || (isalpha(*p) && (p - in) > 0 && isspace(p[-1]))
|| (islower(*p) && p == in)) {
out[zbPosOut++] = *p; /* ... then the letter is the start letter
of a word, so add it to our `out` array, and
increment the current `zbPosOut` */
}
}
out[zbPosOut] = 0; /* null-terminate the out array */
}
This code says a lot in few lines. Let's take a look:
isupper(*p) || (isalpha(*p) && (p - in) > 0 && isspace(p[-1]))
|| (islower(*p) && p == in)
If the current character (*p) is an uppercase character OR if it is alphabetc (isalpha(*p) and the previous character p[-1] is a space, then we may consider *p to be the first character of a word, and it should be added to our out array. We include the test (p - in) > 0 because if p == in, then we are at the zero position of the array and therefore p[-1] is undefined.
The order in this expression matters a lot. If we were to put (p - in) > 0 after the isspace(p[-1]) test, then we would not be taking advantage of the laziness of the && operator: as soon as it encounters a false operand, the following operand is not evaluated. This is important because if p - in == 0, then we do not want to evaluate the isspace(p[-1]) expression. The order in which we have written the tests makes sure that isspace(p[-1]) is evaluated after making sure we are not at the zero position.
The final expression (islower(*p) && p == in) handles the case where the first letter is lowercase.
out[zbPosOut++] = *p;
We append the character *p to the out array. The current position of out is kept track of by the zbPosOut variable, which is incremented afterwards (which is why we use postscript ++ rather than prefix).
Code to test the operation of abbrev:
int main()
{
char jordan1[] = " electronic frontier foundation ";
char out[16];
abbrev(jordan1, out);
puts(out);
return 0;
}
It gives eff as the output. For it to look like an acronym, we can change the code to append the letter *p to out to:
out[zbPosOut++] = toupper(*p);
which capitalizes each letter added to the out array (if *p is already uppercase, toupper just returns *p).
void print_without_duplicate_leading_trailing_spaces(const char *str)
{
while(*str == ' ' && *str) str++;
while(*str)
{
if(*str != ' ' || (*str == ' ' && *(str + 1) != ' ' && *str))
{
putchar(*str);
}
str++;
}
}
What you want to do could be simplified with a for() loop.
#include <stdio.h>
#include <string.h>
void abbrev(const char s[], char a[], size_t size) {
int pos = 0;
// Loop for every character in 's'.
for (int i = 0; i < strlen(s); i++)
// If the character just before was a space, and this character is not a
// space, and we are still in the size bounds (we subtract 1 for the
// terminator), then copy and append.
if (s[i] != ' ' && s[i - 1] == ' ' && pos < size - 1)
a[pos++] = s[i];
printf("%s\n", a); // Print.
}
void main() {
char jordan1[] = " Electronic Frontier Foundation ";
char a[5];
size_t size = 5;
abbrev(jordan1, a, size);
}
However, I don't think this is the best way to achieve what you are trying to do. Firstly, char s[0] cannot be gotten due to the check on the previous character. Which brings me to the second reason: On the first index you will be checking s[-1] which probably isn't a good idea. If I were implementing this function I would do this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void abbrev(const char s[], char a[], size_t size) {
char *str = strdup(s); // Make local copy.
size_t i = 0;
// Break it up into words, then grab the first character of each word.
for (char *w = strdup(strtok(str, " ")); w != NULL; w = strtok(NULL, " "))
if (i < size - 1)
a[i++] = w[0];
free(str); // Release our local copy.
printf("%s\n", a);
}
int main() {
char jordan1[] = "Electronic Frontier Foundation ";
char a[5];
size_t size = 5;
abbrev(jordan1, a, size);
return 0;
}
I have a class that is meant to return a char** by splitting one char* into sentences. I can allocate the memory and give it values at a certain point, but by the time I try to return it, it's completely missing.
char **makeSentences(char *chapter, int *nSentences){
int num = *nSentences;
char* chap = chapter;
char **sentences;
sentences = (char**) malloc(sizeof(char*) * num);
int stops[num + 1];
stops[0] = 0;
int counter = 0;
int stop = 1;
while (chap[counter] != '\0'){
if (chap[counter] == '.'){
stops[stop] = counter + 1;
printf("Place: %d\nStop Number: %d\n\n", counter, stop);
stop++;
}
counter++;
}
for (int i = 0; i < num; i++){
int length = stops[i+1] - stops[i];
char characters[length+1];
memcpy(characters, &chap[stops[i]], length);
characters[length] = '\0';
char *sentence = characters;
sentences[i] = sentence;
printf("%s\n",sentence);
printf("%s\n", sentences[i]);
}
char* testChar = sentences[0];
printf("%s\n", sentences[0]);
printf("%s]n", testChar);
return sentences;
}
The last two printing lines don't print anything but a newline, while the exact same lines (in the for loop) print as expected. What is going on here?
The problem is these three lines:
char characters[length+1];
char *sentence = characters;
sentences[i] = sentence;
Here you save a pointer to a local variable. That variable characters will go out of scope every iteration of the loop, leaving you with an "array" of stray pointers.
While not standard in C, almost all systems have a strdup function whichg duplicates a string by calling malloc and strcpy. I suggest you use it (or implement your own).
I am trying to create a program that is able to rotate at point k, defined as the "rotation requested."
Example: rotate("derp", 3) => pder
My code for this function is called rotate, as listed below. It takes in both a char pointer array, startString, as defined in my main, and the number of rotations (A long int because I use atol to get the integer from the command line).
int rotate(char *startString, long int rotations) {
char *doubleString = malloc((sizeof startString * 2) + sizeof(char));
strcat(doubleString, startString);
strcat(doubleString, startString);
long int stringSize = (sizeof startString - 1);
long int breakIndex = (rotations % stringSize);
char* rotatedString = malloc((sizeof startString + sizeof(char)));
int i;
for (i = 0; i < stringSize + 1; i++) {
char pushedCharacter = doubleString[(int)breakIndex + i];
strcat(rotatedString, &pushedCharacter);
}
printf("%s\n", rotatedString);
printf("%s\n", doubleString);
return 0;
}
But, when I output, if I use something like doghouse I get a weird ?4??? in front of the output for the rotatedString. It also completely doesn't work for derp, instead printing out pderp with the same ?4??? in front. Where is this runtime error being caused?
EDIT
The answer given was correct, but the goal was to be able to accept rotations greater than the length of the given string. That code is below:
void rotate(char * startString, long int rotations) {
long int stringSize = strlen(startString);
long int breakIndex = (rotations % stringSize);
char *rotatedString = malloc(stringSize + 1); //counting extra char for null terminator
strncpy(rotatedString, startString + breakIndex, stringSize - breakIndex);
strncpy(rotatedString + stringSize - breakIndex, startString, breakIndex);
rotatedString[stringSize] = '\0'; // for the ending null character of the char array
printf("Result: %s\n", rotatedString);
free(rotatedString);
}
Your doublestring initialization allocates too little memory because you're using sizeof(startstring), which is the size of a pointer, not strlen(startstring) + 1 which is the length of the string including the terminating NUL character. This means your code is overwriting the end of the buffer with hilarous results. Try the following:
void rotate(char * startString, int rotation) {
int len = strlen(startString);
if (len == 0 || len <= rotation)
return;
char *rotatedString = malloc(len + 1); /* One extra char for the terminating NUL */
strncpy(rotatedString, startString + rotation, len - rotation);
strncpy(rotatedString + len - rotation, startString, rotation);
rotatedString[len] = '\0';
printf("%s\n", rotatedString);
free(rotatedString); /* don't leak memory! */
}