what is wrong with my reverse function - c

I'm trying to writing a function to reverse a string: If the string input is "Hello World", the function should return "dlroW olleH". However, when I run my function the string stays the same:
void reversestring(char* s) {
char tmp; //tmp storing the character for swaping
int length; //the length of the given string
int i; //loop counter
//reverse the string of even length
length = strlen(s);
if (length % 2 == 0) { //if the length of the string is even
for(i = 0; i < (int) (length / 2);i++) {
tmp = s[length - i];
s[length - i] = s[i];
s[i] = tmp;
}
}
//reverse the string of odd length
if (length % 2 == 1) { //if the length of the string is odd
for(i = 0; i < (int) ((length + 1) / 2);i++) {
tmp = s[length + 1];
s[length + 1] = s[i];
s[i] = tmp;
}
}
}

You only need one loop to deal with strings. And the symmetric character of s[i] is s[length-i-1],
void reverse(char* s) {
char tmp; //tmp storing the character for swaping
int length; //the length of the given string
int i; //loop counter
//reverse the string of even length
length = strlen(s);
if (length < 2) return;
for(i = 0; i < (int) (length / 2);i++){
tmp = s[length - i - 1];
s[length - i - 1] = s[i];
s[i] = tmp;
}
}
Exemple:
abcde
01234
length is 5, length / 2 is 2 (integer division). length is odd, but you don't have to move the central character. Characters that need to be swapped
(0,4), (1,3)
Test:
int main () {
char x[] = "Hello World";
reverse(x);
printf("%s \n",x );
return 0;
}
prints
dlroW olleH

You are off by one in indexing. The symmetric of s[0] is not s[length- 0] , but s[length-0-1].
As for the odd case I don't get it what exactly you try to do but it seems you easily go out of bounds on each iteration.

Related

String allocated with malloc is only returning the first character

I'm writing a function to rearrange a string's characters. I allocated the new string with malloc and initialize it, and then return it. But when I return it, it always only returns the first character.
I've tried printing the characters of the new string one by one and they print out correctly, but when I call the function, only the first character is returned. I can't figure out why. Any help would be appreciated!
Here's my code:
char * solution(char * s) {
int len = strlen(s);
int i;
int index = 0;
char *ans = (char *) malloc(sizeof(char) * (len + 1));
if (ans == NULL) {
fprintf(stderr, "Ran out of space in some function \n");
exit(1);
}
//char* ans = (char *) malloc(len + 1);
ans[len] = '\0';
for(i = 0; i < len/2; i++){
ans[index++] = s[i];
ans[index++] = s[len - i];
}
if(len % 2 == 1){
ans[index] = s[len/2];
}
return ans;
}
In the first iteration of this for loop
for(i = 0; i < len/2; i++){
ans[index++] = s[i];
ans[index++] = s[len - i];
}
the character ans[1] is set to s[len] (i is equal to 0 in the first iteration of the loop) that is to '\0'.
As a result you will get a string that contains only one character.
What you do is what you get.:)
It seems you mean
ans[index++] = s[len - i - 1];
Pay attention to that as the source string is not changed within the function then the function should be declared like
char * solution( const char * s );
The original declaration
char * solution(char * s);
means that the string will be changed in place.
If you want to change a string in place then the function can look the following way as shown in the demonstration program below.
#include <string.h>
#include <stdio.h>
char * solution( char *s )
{
size_t n = strlen( s );
for (size_t i = 1; i < n; i += 2)
{
char c = s[n - 1];
memmove( s + i + 1, s + i, n - i - 1);
s[i] = c;
}
return s;
}
int main( void )
{
char s[] = "0123456789";
puts( s );
puts( solution( s ) );
}
The program output is
0123456789
0918273645

C: the pointer to pointer issue

Following is my code, I want to use pointer to pointer to store strings.
char **BlankWords(char word[]){
// take word 'lad' as an example
// length of it is 3
// fill in blank: _ad, l_d, la_, _lad, l_ad, la_d, lad_
// 3 + 4 = 7
// which means, length of 'lad' + (length of 'lad') + 1
int strLength = strlen(word);
char **blank_words = malloc(sizeof(char*) * (2 * strLength + 1));
assert(blank_words != NULL);
int i, j, k;
for (i = 0; i < strLength; i++){
// allocate memory for each length of the word
blank_words[i] = calloc(MAX_WORD_LENGTH, sizeof(char));
assert(blank_words[i] != NULL);
char temp[MAX_WORD_LENGTH];
strcpy(temp, word);
temp[strLength] = '\0';
temp[i] = '_';
blank_words[i] = temp;
// printf("%s\n", blank_words[0]);
}
for (j = strLength; j < (2 * strLength + 1); j++){
// allocate memory for each length of the word
blank_words[j] = calloc(MAX_WORD_LENGTH, sizeof(char));
assert(blank_words[j] != NULL);
char temp[MAX_WORD_LENGTH];
strcpy(temp, word);
temp[(strlen(temp) + 1)] = '\0';
for (k = (strLength - 1); k >= (j - strLength); k--){
if (k >= 0){
temp[k + 1] = temp[k]; // in order to insert '_' to the word, then the other letter move back one
}
}
temp[j - strLength] = '_'; // insert '_' to the word
blank_words[j] = temp;
}
return blank_words;
}
Following is the output, each row was overwritten after each loop, but in my opinion, each row cannot be overwritten, and may store a unique string.
blank_words[0]: lab_
blank_words[1]: lab_
blank_words[2]: lab_
blank_words[3]: lab_
blank_words[4]: lab_
blank_words[5]: lab_
blank_words[6]: lab_
I don't know why the previous data gets overwritten after each loop. In my opinion, the output should be:
blank_words[0]: _ab
blank_words[1]: l_b
blank_words[2]: la_
blank_words[3]: _lab
blank_words[4]: l_ab
blank_words[5]: la_b
blank_words[6]: lab_
As others have said, a local buffer disappears when its scope closes. Since the char** array points to buffers of that sort, the result is undefined behavior. You'll need to allocate the result strings with malloc.
Another tip: You can build the second set of strings by just moving the underscore rather than creating each from scratch. This is simpler:
#include <stdlib.h>
#include <string.h>
#include <assert.h>
void *safe_malloc(size_t n) {
void *r = malloc(n);
assert(r);
return r;
}
char *stralloc(char *s) {
return strcpy(safe_malloc((strlen(s) + 1) * sizeof(char)), s);
}
char **variations(char *s) {
int len = strlen(s), rp = 0;
char **r = safe_malloc((2 * len + 1) * sizeof *r);;
char buf[len + 2];
strcpy(buf, s); // Copy in case s is a read-only literal.
for (int i = 0; i < len; ++i) {
char t = buf[i]; // Remember the i'th char.
buf[i] = '_'; // Overwrite with _.
r[rp++] = stralloc(buf); // Capture a copy.
buf[i] = t; // Replace original char.
}
buf[0] = '_'; // Make the 1st char _.
strcpy(buf + 1, s); // Copy the rest after.
r[rp++] = stralloc(buf); // Capture a copy.
for (int i = 0; i < len; ++i) {
buf[i] = buf[i + 1]; // Overwrite _ with following char.
buf[i + 1] = '_'; // Move the _ up one position.
r[rp++] = stralloc(buf); // Capture a copy.
}
return r;
}

int to string conversion not working properly

I'm trying to create a function that converts an integer into a string, basically what have I done is the following functions: when we get the numbers from the conversion they are reversed so I need a reverse function to make them in the right way. The intostring uses (I think? I got it from some website) the ascii table to convert the number into the string desired.
The problem is: when I enter the 2-digit number they are reversed the wrong way (I guess my reverse function doesn't work that well) and after a certain number of digit the conversion it's not any more accurate.
reverse function:
char reverse(char *stringa) {
int len = strlen(stringa) - 1;
for(int i = 0; i < len / 2; i++) {
char tmp = stringa[i];
stringa[i] = stringa[len - i];
stringa[len - i] = tmp;
}
}
intostring function:
void intostring(int num, char *str) {
int i = 0;
while (num != 0) {
int rem = num % 10;
str[i++] = (rem > 9)? (rem-10) + 'a' : rem + '0';
num = num / 10;
}
str[i] = '\0';
reverse(str);
}
The condition i<len/2 in the reverse function is wrong.
For example, if the string is 2-digit long, len will be 1 and len/2 will be 0. Therefore, no swap will occure while the two characters should be swapped.
the condition should be i<=len/2 or i<len-i.
/*
It works clearly . Checked.
*/
void reverse(char source[],char destination[]) {
int x,i;
//start from last char
i = i=(strlen(source)-1
for (x=0;x<strlen(source);x++){
//Insert char at i in source to x in destination
destination[x]=source[i];
destination[x]='\0';
i--;
}
}
There are multiple problems:
the reverse function fails for an empty string. You should not subtract 1 from the length, but adjust the offset inside the loop.
reverse is defined to return a char but does not return anything. Make it return a char * and return stringa.
intostring produces an empty string for num <= 0. You should loop while num > 9 and add the final digit after the loop.
intostring converts the digit into a character for bases up to 36 (assuming ASCII). This is unnecessarily complex since the base is 10. Use a simpler conversion: str[i++] = '0' + rem;
it may be useful for intostring to return a pointer to the destination array.
Here is a modified version:
#include <string.h>
char *reverse(char *str) {
size_t len = strlen(str);
for (size_t i = 0; i < len / 2; i++) {
char tmp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = tmp;
}
return str;
}
char *intostring(int num, char *str) {
int i = 0;
if (num >= 0) {
while (num > 9) {
str[i++] = '0' + num % 10;
num = num / 10;
}
str[i++] = '0' + num;
} else {
while (num < -9) {
str[i++] = '0' - num % 10;
num = num / 10;
}
str[i++] = '0' - num;
str[i++] = '-';
}
str[i] = '\0';
return reverse(str);
}
Here is an alternative approach for the reverse function using 2 index variables:
#include <string.h>
char *reverse(char *str) {
size_t i = 0;
size_t j = strlen(str);
while (j --> i) {
char c = str[j];
str[j] = str[i];
str[i++] = c;
}
return str;
}
The reverse function condition is worng.
If the integer in 32 then the string will be
s[0] = '2', s[1] = '3', s[2] = '\0' before string reversal.
so in reverse function the following swap operation has to be applied as
if number = 32 then len = 2
i = 0 then len - i - 1 = 1
so 0 and 1 will be swaped.
void reverse(char *stringa){
int len = strlen(stringa);
for(int i = 0; i < len / 2; i++){
char tmp = stringa[i];
stringa[i] = stringa[len - i - 1];
stringa[len - i - 1] = tmp;
}
}
void intostring(int num, char *str)
{
int i = 0;
if(num == 0){
str[i++] = '0';
str[i] = '\0';
}
else if(num > 0){
while(num != 0){
int rem = num % 10;
str[i++] = '0' + rem;
num = num/10;
}
str[i] = '\0';
}
else{
while(num != 0){
int rem = num % 10;
/*
(-5/2) => -2
-2 * 2 => -4
so a%b => -1
(5/-2) => -2
-2 * -2 => 4
so a%b => 1
*/
rem = abs(rem); // as the rem value is negative
str[i++] = '0' + rem;
num = num/10;
}
str[i++] = '-';
str[i] = '\0';
}
reverse(str);
}
Your reverse function is wrong. You can make it correct (and readable) like below:
void reverse(char *stringa) {
int i = 0; //Forwarding moving index
int j = strlen(stringa) - 1; // the end index
int tmp; // Edited to get the code compiled
for (; i < j; i++, j--) {
tmp = stringa[i];
stringa[i] = stringa[j];
stringa[j] = tmp;
}
}

Segfault 11 on long string, PRIOR to accessing string, only when string > 14

ANSI c on OSX 10.13.6
Apple LLVM version 9.1.0 (clang-902.0.39.2)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
I'm learning c
This is a function that manually (character-by-character) adds two character strings representing large numbers (that exceed the unsigned long long or double size).
It functions fine with any two strings 14 or less characters long, but segmentation fault 11 with any strings greater than 14 chars.
Changing the string's memory allocation method seems to have no effect (I.e. from char[15] addend1; // not a ptr to char *addend1 = (char *) malloc(sizeof(char) * (16) ); // pointer
One things that's curious, is that it seems to segfault on the ...
for (int j = maxlength - 1 ; j >= 0; j--)
... prior to accessing either of addend1 or addend2, but I'm not able to find an error there or change it to prevent the segfault.
Am I misreading where the error arises, or could it be related to the for loop?
Successful run (less than 15 chars)
maxlength = 14
char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) ) ... DONE
for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } ... DONE
Start adding individual ints from end (right side) ...
13 ...12 ...11 ...10 ...9 ...8 ...7 ...6 ...5 ...4 ...3 ...2 ...1 ...0 ...main.sum = 28147497671064
UNSuccessful run (15 chars)
maxlength = 15
char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) ) ... DONE
for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } ... DONE
Start adding individual ints from end (right side) ...
Segmentation fault: 11
MAIN.c
#include <stdio.h>
#include <stdlib.h>
#include "../../c-library/include/addViaStrings.h"
int main(void) {
// s[0] = 72; s[1] = 101; s[2] = 108; s[3] = 108; s[4] = 111; s[5] = 32; s[6] = 87; s[7] = 111; s[8] = 114; s[9] = 108; s[10] = 100; s[11] = 0;
// WORKS
// char s1[] = "14073748835532";
// char s2[] = "14073748835532";
// FAILS
char s1[] = "140737488355328";
char s2[] = "140737488355328";
char *sum = addNumericStrings(&s1, &s2);
printf("main.sum = %s\n", sum);
}
addViaStrings.h
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
char* addNumericStrings(char *s1, char *s2);
char leftPad(char *result, char *s, int maxlength);
int findMaxLength(char *s1, char *s2);
char* addNumericStrings(char *s1, char *s2){
// Find the length of the greater of the two
int maxlength = findMaxLength(s1, s2);
printf("maxlength = %d\n", maxlength); //333
///////////////////////////////////////////////
// Using malloc instead of char[maxlength] seems to have NO EFFECT on the issue
// char addend1[maxlength]; // not a pointer
char *addend1 = (char *) malloc(sizeof(char) * (maxlength + 1) );
addend1[maxlength + 1] = 0; // end flag
// char addend2[maxlength]; // not a pointer
char *addend2 = (char *) malloc(sizeof(char) * (maxlength + 1) );
addend2[maxlength + 1] = 0; // end flag
// Allocate sum pointer
printf("char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) ) ... "); //333
char *sum = (char *) malloc(sizeof(char) * (maxlength + 1) );
printf("DONE\n"); //333
// General use vars
int a1, a2, total;
int carry = 0;
// Prepare the strings for manual addition. Pad the left with char 0s
leftPad(addend1, s1, maxlength);
leftPad(addend2, s2, maxlength);
// Buffer sum with zeros
sum[maxlength + 1] = 0; // end flag
printf("for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } ... "); //333
for (int i = 0; i < (maxlength); i++) { sum[i] = '0'; } // Fill w/ 0s
printf("DONE\n"); //333
// Run the manual addition
// Start adding individual ints from end (right side)
printf("Start adding individual ints from end (right side) ...\n"); //333
// maxlength -1 because(I think) the termination char takes 2 bytes
// If I use (maxlength) instead of (maxlength -1) I get a weird
// question mark char at the end of returnsum
for (int j = maxlength - 1 ; j >= 0; j--) {
///////////////////////////////////////////
// The segfault seems to happen BEFORE accessing addend1 or addend2
printf("%d ...", j); // 333 This DOES NOT print
///////////////////////////////////////////
a1 = addend1[j] - '0'; // Convert to int
a2 = addend2[j] - '0'; // Convert to int
total = (a1 + a2 + carry);
carry = 0;
if ( total >= 10){
carry += 1;
total -= 10;
}
sum[j + 1] = '0'+total; // convert to ascii value for numbers (adding 48)
}
sum[0] = '0' + carry; // add last carry to start of num always, even if 0
// Before returning, truncate leading zeros
char *returnsum = (char *) malloc(sizeof(char) * (strlen(sum) + 1) );
int sum_i = 0;
int returnsm_i = 0;
// bool truncate = true; // Find out why this wont compile
int truncate = 1; // true
while (1){
// if order is important here
if (sum[sum_i] == '\0') { break; } // we're done
if (sum[sum_i] == '0' && truncate == 1) { sum_i += 1; continue; } // 1 is true
// if a num, Stop truncating 0s but DO continue adding numbers
if (sum[sum_i] != '0') { truncate = 0; } // 0 is false
returnsum[returnsm_i] = sum[sum_i];
returnsm_i += 1;
sum_i += 1;
}
return returnsum;
}
char leftPad(char *result, char *s, int maxlength){
int slength = strlen(s);
// buffer with zeros, not '\0's
for (int i = (maxlength); i >= 0; i--){ result[i] = '0'; }
// right fill result with s
for (int j = 0; j <= slength; j++){
int index = ((maxlength - slength) + j);
result[index] = s[j];
}
result[maxlength + 1] = 0;
}
int findMaxLength(char *s1, char *s2){
// int length1 = findEndLength(s1);
// int length2 = findEndLength(s2);
int length1 = strlen(s1);
int length2 = strlen(s2);
int maxlength;
(length1 > length2) ? (maxlength = length1) : (maxlength = length2);
return maxlength;
}
The issue was I was trying to access the sum string as if it was one position longer than the addends strings, but I had declared it as the same length (I.e. maxlength + 1). So I was attempting to access one position past the actual sum array.
This was a somewhat hidden problem, because it was not until the length of sum needed to be greater than 15, that this access error stepped into disallowed memory space, resulting in a segfault.
Details
Because the sum of two addends could conceivably require at least one additional position in the array if the sums carried over a one (I.e. 999 + 999 = 1998), the sum string needs to be one array position longer than the addends.
If the addends were 3 digits long (length of array = 4) then the sum needed to be 4 digits long (array length = 5).
// Correct code if "maxlength" (number of actual digits in string) = 14
char *addend1 = (char *) malloc(sizeof(char) * (maxlength + 1) ); // +1 To include termination byte
char *addend2 = (char *) malloc(sizeof(char) * (maxlength + 1) ); // +1 To include termination byte
char *sum = (char *) malloc(sizeof(char) * (maxlength + 2) ); // +2 To include termination byte, AND an extra char at the front
...so that the final actual digit character of sum is accessed via maxlength + 1
CORRECTED CODE
NOTE: Because calculating against maxlength as the number of digits (versus the length of the entire array including terminator) was confusing - as well as considered bad form, I have since learned - the following final code has been simplified to use more intuitive variables.
#include <stdio.h>
#include <stdlib.h>
char* addIntsAsStrings(char *s1, char *s2);
char* addIntsAsStrings(char *s1, char *s2){
// Find the length of the greater of the two
int length1 = strlen(s1);
int length2 = strlen(s2);
int addendDigits;
(length1 > length2) ? (addendDigits = length1) : (addendDigits = length2);
// We need separate strings of so they can be buffered with zeros
// Create the string for the addends and buffer with zeros.
char addend1[addendDigits + 1];
char addend2[addendDigits + 1];
for (int i = 0; i < (addendDigits) ; i++){ // "<" not "<="
addend1[i] = '0'; // buffer w/ 0s
addend2[i] = '0'; // buffer w/ 0s
} // buffer w/ 0s
addend1[addendDigits] = '\0'; // terminate
// put s1 and s2 into buffered addends strings
int s1_index = (strlen(s1) - 1);
int s2_index = (strlen(s2) - 1);
for (int i = (addendDigits - 1); i >= 0; i--){ //Start at back of addend
if ( s1_index >= 0) { addend1[i] = s1[s1_index]; }
if ( s2_index >= 0) { addend2[i] = s2[s2_index]; }
s1_index -= 1;
s2_index -= 1;
}
// Allocate sum pointer. The sum pointer needs to be ONE char
// longer than the addends, in the event that the addends need
// to carry a final one to the front. I.e. 999 + 999 = 1998
int sumDigits = addendDigits + 1;
char *sum = (char *) malloc(sizeof(char) * (sumDigits + 1) ); // +1 To include termination byte, AND an extra char at the front
for (int i = 0; i < (sumDigits) ; i++){ // "<" not "<="
sum[i] = '0'; // buffer w/ 0s
}
sum[sumDigits] = '\0';
// Manual addition vars
int a1, a2, total;
int carry = 0;
// Run the manual addition
// Start adding individual ints from end (right side)
for (int j = addendDigits - 1; j >= 0; j--) {
a1 = addend1[j] - '0'; // Convert to int
a2 = addend2[j] - '0'; // Convert to int
total = (a1 + a2 + carry);
carry = 0;
if ( total >= 10){
carry += 1;
total -= 10;
}
// convert to ascii value for numbers (adding 48)
sum[j + 1] = '0'+total; // sum[j + 1] because `sum`is always one index larger than the addends
}
sum[0] = '0' + carry; // add last carry to start of num always, even if 0
// Before returning, truncate leading zeros
char *returnsum = (char *) malloc(sizeof(char) * (strlen(sum) + 1) );
int sum_i = 0;
int returnsm_i = 0;
int truncate = 1; // true
while (1){
// if order is important here
if (sum[sum_i] == '\0') { break; } // we're done
if (sum[sum_i] == '0' && truncate == 1) { sum_i += 1; continue; } // 1 is true
// if a num, Stop truncating 0s but DO continue adding numbers
if (sum[sum_i] != '0') { truncate = 0; } // 0 is false
returnsum[returnsm_i] = sum[sum_i];
returnsm_i += 1;
sum_i += 1;
}
return returnsum;
}

String is not being filled with random chars (C)?

I'm trying to fill a string with characters from the string 'reset\0' but randomized. For some reason it only gives me one character bacK:
#define STR_LEN 6
char *inputString()
{
char *string[STR_LEN + 1] = {0};
const char *digits = "reset\0";
int i;
for (i = 0; i < STR_LEN; i++)
{
string[i] = digits[ rand() % 5 + 0 ];
}
printf("STRING: %s\n", string);
}
prints only one character like 't' or 'e' to the console. What am I doing wrong?
If you mean making a random permutation of characters, not just using the source string as an alphabet, consider Fisher–Yates shuffle. An implementation could be like this:
char s[] = "reset";
for (size_t i = strlen(s) - 1; i > 0; i--)
{
size_t j = rand() % (i + 1);
char t = s[i];
s[i] = s[j];
s[j] = t;
}
printf("%s\n", s);
The idea is to go from right to left, and on every step to swap the element at index i with an element at random index j between 0 and i, inclusive.
Corrected code
#define STR_LEN 5
char *inputString()
{
char string[STR_LEN + 1] = {0};
const char *digits = "reset";
int i;
for (i = 0; i < STR_LEN; i++)
{
string[i] = digits[ rand() % 5 + 0 ];
}
printf("STRING: %s\n", string);
}
But note that this doesnt do what you want, it print 5 random chars from 'reset' so 'ssere' can be output

Resources