C: reverse string function not affecting pointer - c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int reverse(char *, int);
main()
{
char *word = "Thanks for your help";
reverse(word, strlen(word));
printf("%s", word);
getchar();
}
int reverse(char *line, int len)
{
int i, j;
char *newline = malloc(strlen(line));
for (i = len - 1, j = 0 ; i >= 0; i--, j++)
{
newline[j] = line[i];
}
newline[j] = '\0';
line = &newline;
}
Hey folks. I've got a simple C question that I can't seem to solve.
The program above is meant to take in a string and print it out backwards. Reverse is the function by which this is done.
The issue, specifically, is that when I print word in main(), the string appears unchanged. I've attempted to make the address of line the address of newline, but it doesn't have any effect.

int reverse(char *line, int len)
{
int i, j;
char *newline = malloc(strlen(line));
for (i = len - 1, j = 0 ; i >= 0; i--, j++)
{
newline[j] = line[i];
}
newline[j] = '\0';
line = &newline; // Your problem is here
}
You're merely assigning to the local line pointer. This has no effect on the calling function whatsoever.
Consider instead:
char *reverse(char *line, int len)
{
// ...
return newline;
}
Additional advice:
Turn on compiler warnings, and heed them. You've got lots of little things wrong (e.g. reverse isn't currently returning anything, but is declared as returning int).
Given that the first argument of reverse is a pointer to a C string (NUL-terminated), there's no need to take a length argument as well.
A reverse function doesn't necessarily need to be defined as returning a copy of the string, reversed. It could instead reverse a string in-place. Note that you cannot pass a string literal to a function like this, as they are read-only.
Here's how I would write this:
#include <stdio.h>
#include <string.h>
void reverse(char *str)
{
size_t i, j;
for (i = strlen(str) - 1, j = 0 ; i > j; i--, j++)
{
// Swap characters
char c = str[i];
str[i] = str[j];
str[j] = c;
}
}
int main(void)
{
// Mutable string allocated on the stack;
// we cannot just pass a string literal to reverse().
char str[] = "Here is a test string";
reverse(str);
printf("Result: \"%s\"\n", str);
return 0;
}
Note that the for loop condition is i > j, because we want each to only traverse half the array, and not swap each character twice.
Result:
$ ./a.exe
Result: "gnirts tset a si ereH"

Take a look at the code below:
void addOne(int a) {
int newA = a + 1;
a = newA;
}
int main() {
int num = 5;
addOne(num);
printf("%d\n", num);
}
Do you see why that will print 5, and not 6? It's because when you pass num to addOne, you actually make a copy of num. When addOne changes a to newA, it is changing the copy (called a), not the original variable, num. C has pass-by-value semantics.
Your code suffers from the same problem (and a couple other things). When you call reverse, a copy of word is made (not a copy of the string, but a copy of the character pointer, which points to the string). When you change line to point to your new string, newLine, you are not actually changing the passed-in pointer; you are changing the copy of the pointer.
So, how should you implement reverse? It depends: there are a couple options.
reverse could return a newly allocated string containing the original string, reversed. In this case, your function signature would be char *reverse, instead of int reverse.
reverse could modify the original string in place. That is, you never allocate a new string, and simply move the characters of the original string around. This works, in general, but not in your case because char pointers initialized with string literals do not necessarily point to writable memory.
reverse could actually change the passed-in pointer to point at a new string (what you are trying to do in your current code). To do this, you'd have to write a function void reverse(char **pointerToString). Then you could assign *pointerToString = newLine;. But this is not great practice. The original passed-in argument is now inaccessible, and if it was malloc'd, it can't be freed.

Related

C - String Reversal Function with Pointers Not Running

I understand that issues with string-reversal in C are numerous on this site, but I seem to be having a uniquely odd problem: the reversal logic simply does not run despite seeming to be set up correctly.
I wanted to write a program to reverse a given string in-place, by moving two pointers from the front and back of the string together:
void reverse_inplace_pointer(char *string_in, int length) {
char *back_ptr = string_in + (length - 1);
for (int i = 0; i < length / 2; i++) {
char swap_char = *back_ptr;
/* Dereference pointers to double-check values */
printf("\nCurrent front char: %c\nCurrent back char: %c", *string_in, *back_ptr);
/* Swap */
*back_ptr = *string_in;
*string_in = swap_char;
printf("\nSwap %u successful.", i + 1);
string_in++;
back_ptr--;
}
}
Calling this with a test string:
char *test_string = "TestMeTestMe";
nets the result:
Current front char: T
Current back char: e
And then execution just stops, at the assignment of the character pointed to by *string_in to the location pointed to by *back_ptr. If I remove the assignment, the program will quite happily move the pointers along the test string and print out each character without issue.
I looked for other examples of reassigning elements in arrays and found the logic in tutorials to be almost identical to mine. I copied this example wholesale as a test:
void steal_this_function(char *string) {
printf("\nEntering function:");
int length, c;
char *begin, *end, temp;
length = strlen(string);
begin = string;
end = string;
for (c = 0; c < (length - 1); c++) {
end++;
}
for (c = 0; c < length / 2; c++) {
temp = *end;
*end = *begin;
*begin = temp;
begin++;
end--;
}
}
The result is the same - it stops on the first iteration and the program exits. The only difference here is the reuse of the original pointer string, which is then walked to the end of the string with a for-loop.
Clearly I have some confusion here with pointers, but my understanding was that *back_ptr = *string_in; effectively says dereference the pointer string_in, then go to the location pointed to by back_ptr and store whatever it contains there.
I'm also compiling with the -Wall flag on GCC and it isn't finding any issues. This is frustrating because it should be very simple.
the function requires modifiable char array. It cannot be called when parameter is a pointer to thestring literal.
Some additional remarks.
This kind of function should return the reversed string. It is possible to use it as a parameter of another functions.
strlen returns size_t not int. Use the correct type in the loops as well
#include <string.h>
#include <stdio.h>
char *reverse(char *str)
{
char *end = str + strlen(str) - !!*str;
char *wrk = str;
while(end > wrk)
{
char tmp = *wrk;
*wrk++ = *end;
*end-- = tmp;
}
return str;
}
int main(void)
{
char str[] = "0123456789";
printf("%s\n", reverse(str));
}
Calling this with a test string: char *test_string = "TestMeTestMe";
That's the culprit, as noted in the comments, it declares a pointer to the memory where the string literal "TestMeTestMe" is stored, which you are not allowed to modify.
You should declare an array instead.
char test_string[] = "TestMeTestMe"; // Now test_string is a modifiable
// NULL-terminated char[13]
I'm also compiling with the -Wall flag on GCC and it isn't finding any issues.
-Wall it's not enough, but you can use -Wwrite-strings to catch this particular issue (see e.g. here).

c function convert "fffoootoo" to "foto" (leaves out following repeating characters)

The task would be to remove following characters that are repeating from a char array, like "deeeciddeee" -> "decide" or "phhhonne" -> "phone".
I have a function that crashes the console, and I can't spot the bug:
char* my_unique(char *first, char *last) {
char* ret=first;
for(int i=0; first+i!=last; i++){
if(first[i]==first[i+1]){
for(int j=i; first+j!=last; j++)
first[j]=first[j+1];
last--;
}
}
return ret;
}
it is called this way:
char* a="oooat";
a=my_unique(a, a+strlen(a));
cout<<a;
please help me!
Besides a small bug (you should add the line i--; after last--;, because you're deleting the character at possition i, so what has been the character at i+1 became the new character at possition i. If you don't decrease i, it will be increased and you jump over a character) the code runs perfectly fine IF it is called with
const char* b = "oooat";
char* a = new char[strlen(b) + 1];
for (size_t c = 0; c < strlen(a) + 1; c++) { a[c] = b[c]; }
a = my_unique(a, a + strlen(a));
cout << a;
delete[] a;
Notice that I've used a edit-able copy of the string, as the literal itself is of type const char* and therefor can't be changed at all. And as I said, this works perfectly fine and prints "oat", just as expected, without any crash. So your problem might be that you try to edit a const string literal? In that case you might consider to copy it, as I did, or use std::string (if you code in C++).
There are many beginner mistakes in the code.
Let me point you one by one.
char* a="oooat";
a=my_unique(a, a+strlen(a));
cout<<a;
When you declare a string like this : char* a="oooat", a is a string literal. The memory for the string is allocated into text section of the program. Which basically means you cannot modify the values inside the strings. You can only read from them. Hence when you are passing pointer a to the function and modifying it, it will result in segmentation fault(Illegal access to memory).
Why do you need a ret pointer here? char* ret=first;
You are passing a pointer and modifying the value inside it. Hence the new data will be reflected in the calling function and we need not return it explicitly. So, it is redundant.
Overall logic can be simplified as well
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MYSTR "ooooat"
void my_unique(char *first, char *last) {
int size = last - first;
int i = 0, j = 0, k = 0;
for (; i < size; i++, j++) {
first[j] = first[i];
// Continue to check how many repetitions are there
while (i + 1 < size && (first[i] == first[i+1])) i++;
}
// In the end terminate the string with a NULL.
first[j] = '\0';
return;
}
int main()
{
char a[] = MYSTR;
my_unique(a, a+strlen(a));
printf("%s", a);
return 0;
}
This is in C. There are simpler ways of doing this in C++, and the code can definitely be condensed but has been left simpler for readability.
#include <stdlib.h>
char* fix(char *input) {
char *lookahead = input;
char *newchar, *ret;
// Determine Max Return String Length
int len = 0;
while (*lookahead != '\0') {
len++;
lookahead++;
};
// allocate max possible memory needed and set the pointers
ret = malloc(len);
newchar = ret;
lookahead = input;
*newchar = *lookahead; // copy the first character
while (*lookahead != 0) {
lookahead++; // incrementing this ptr first starts lookahead at 2nd character and
// ensures the null terminator gets copied before the while loop ends
if (*newchar != *lookahead) { // only copy new characters to new return string
newchar++;
*newchar = *lookahead;
};
};
return ret;
};
I'll try to give my answer so that it makes the as little changes as possible to your original code, while using the simplest methods.
The main problem has already been identified by the previous comments - you cannot alter a string literal.
Also, the line of code
i--;
has to be placed as well, with the reason well clarified above.
While making an editable version of the string may be a good way of fixing the problem, a more straightforward way would be to make it a local string, as such :
char b[] = "oooat";
but doing this will make it incompatible with the return type of your my_unique function (char*). But why would you need a return type in the first place, if you are fixing the string itself?
My final code would look like this :
void my_unique(char *first, char *last) {
char* ret=first;
for(int i=0; first+i!=last; i++){
if(first[i]==first[i+1]){
for(int j=i; first+j!=last; j++)
first[j]=first[j+1];
last--;
i--;
}
}
}
making the function return void.
Hope this helps.

function for reversing an array in C (K&R 2nd ed.)

Trying to do Exercise 1-19 of K&R 2nd ed., e.g. writing a function to reverse a string. I thought I managed, but the print output looks strange :-) If I use STRINGSIZE 5 the output is
Original String: hello
Reversed String: ollehhello. If I use STRINGSIZE 6 to keep in mind the '\0' string end character and modify the while-loop to while ((outputString[STRINGSIZE - (i + 2)] = inputString[i]) != '\0'), then I get Original String: hello
Reversed String: olleh?hello, I guess the ? is some random character coming from a '\0' added to the reversed string in the while-loop at position 5; but hello is again added. Could anyone explain how come hello gets added to the end of olleh and how can I get rid of it so that I only get the proper reversed string ?
Here is the code:
#include <stdio.h>
#define STRINGSIZE 5
void reverseString (char inputString[], char outputString[]);
int main(void) {
char stringToReverse[] = "hello";
char reversedString[STRINGSIZE];
reverseString(stringToReverse, reversedString);
printf("Original String: %s\nReversed String: %s\n", stringToReverse, reversedString);
}
void reverseString (char inputString[], char outputString[]) {
int i;
i = 0;
while ((outputString[STRINGSIZE - (i + 1)] = inputString[i]) != '\0')
++i;
}
First, the character array reversedString[] does not have enough space to store the null terminator of the string "hello". One option is to use a variable length array here:
char reversedString[strlen(stringToReverse) + 1];
VLAs were introduced in C99, and made optional in C11. As I remember it, K&R does not include coverage of variable length arrays, since even the 2nd edition was published before this.
Another option that would be compatible with C89 is to use the sizeof operator:
char stringToReverse[] = "hello";
char reversedString[sizeof stringToReverse];
Here, the result from the sizeof operator is known at compile time, and can be used in the declaration of a fixed size array. This size includes space for the null terminator, in contrast to the result from strlen("hello"). Note that this would not work with char *stringToReverse = "hello";, since then the sizeof operator would give the size of a pointer. This also would not work if stringToReverse had been passed into a function first, since then the array name would have decayed to a pointer to the first element of stringToReverse.
In the reverseString() function, the length of inputString needs to be determined (since STRINGSIZE is no longer being used); this can be done with strlen(), or in a loop. Then, critically, the function must be certain to add a null terminator (\0) to outputString[] before returning. Also note that a return statement has been added to the end of main() to make this truly C89 compatible:
#include <stdio.h>
void reverseString (char inputString[], char outputString[]);
int main(void) {
char stringToReverse[] = "hello";
char reversedString[sizeof stringToReverse];
reverseString(stringToReverse, reversedString);
printf("Original String: %s\nReversed String: %s\n",
stringToReverse, reversedString);
return 0;
}
void reverseString(char inputString[], char outputString[])
{
int length = 0;
int i = 0;
/* Get inputString length; or use strlen() */
while (inputString[length] != '\0') {
++length;
}
/* Copy to outputString[] in reverse */
while (i < length) {
outputString[i] = inputString[(length - i) - 1];
++i;
}
/* Add null terminator */
outputString[i] = '\0';
}
First I'll suggest that you change this line:
char reversedString[STRINGSIZE];
to
char reversedString[strlen(stringToReverse) + 1]; // + 1 to make room for the string termination
Then I would do something like:
void reverseString (char inputString[], char outputString[]) {
int i;
int len = strlen(inputString);
for(i=0; i<len; ++i)
{
outputString[len-i-1] = inputString[i];
}
outputString[len] = '\0'; // Terminate the string
}

inverse String in c

i've done a function that inverse a String(array of character) given in parameter , but it's not working , any idea why ?
I'm getting something like this : æIGt(Kt$0#
thanks you
#include <stdio.h>
#include <string.h>
char *
inverse(char *s)
{
int i, taille = strlen(s);
char r[taille];
for (i = 0 ; i < taille ; i++)
{
r[i] = s[taille - i - 1];
}
r[i] = '\0';
return r;
}
int
main()
{
char s[] = "kira";
char *r = inverse(s);
printf("%s",r);
return 1;
}
You are returning a pointer to a local variable. That variable gets destroied when the function inverse returns, so accessing the pointer after the function exits will return invalid data.
It's slightly hard to tell from you question, because you haven't given any outputs, but my best guess is that it's because your returning a pointer to an item on the stack, which will get over-written by the next call, in your case printf. You need to pass inverse a place to put its answer. Try this instead:
#include <stdio.h>
#include <string.h>
void inverse(char *s, char *r)
{
int i,taille=strlen(s);
for(i=0;i<taille;i++)
{
r[i]=s[taille-i-1];
}
r[i]='\0';
}
int main()
{
char s[] = "kira";
char r[sizeof(s)];
inverse(s, r);
printf("%s",r);
return 1;
}
Another standard approach to reversing a string uses pointers to work from both the beginning and end of the string swapping two characters with each iteration. It swaps the original string in place (make a copy if you need to preserve the original, or pass a second string and place the reversed string in there)
/** strrevstr - reverse string, swaps 2 chars per-iteration.
* Takes valid string and reverses, original is not preserved.
* If 's' is valid and non-empty, returns pointer to 's',
* returns NULL otherwise.
*/
char *strrevstr (char *s)
{
if (!s || !*s) { /* validate string is not NULL and non-empty */
printf ("strrevstr() error: invalid string\n");
return NULL;
}
char *begin = s; /* pointers to beginning and end, and tmp char */
char *end = begin + strlen (s) - 1;
char tmp;
while (end > begin) /* swap both beginning and end each iteration */
{
tmp = *end;
*end-- = *begin;
*begin++ = tmp;
}
return s;
}
As you can tell, there are a number of ways to approach the problem, with this and the other answers provided, you should be able to tailor a solution to meet your needs.
There are advantages and disadvantages to every approach. There is nothing wrong with dynamically allocating a new block of memory to hold the reversed string, it just adds an additional responsibility to (1) preserve a pointer to the starting address for the new block so (2) it can be freed when no longer needed. If you need to preserve the original string, passing a pointer to an character array of sufficient size to hold the reversed string is another option preserve the original.
Look over all the answers and let me know if you have any questions.

loop to reverse string in C

So I've looked around on SO and can't find code that answers my question. I have written a function that is supposed to reverse a string as input in cmd-line. Here is the function:
void reverse (char string[]) {
int x;
int i = 0;
char line[strlen(string)];
for (x = strlen(string) - 1; x > 0; x--) {
char tmp = string[x];
line[i] = tmp;
i++;
}
string = line;
}
When I call my reverse() function, the string stays the same. i.e., 'abc' remains 'abc'
If more info is needed or question is inappropriate, let me know.
Thanks!!
You're declaring your line array one char shorter remember the null at the end.
Another point, it should be for (x = strlen(string) - 1; x >= 0; x--) since you need to copy the character at 0.
void reverse (char string[]) {
int x;
int i = 0;
char line[strlen(string) + 1];
for (x = strlen(string) - 1; x >= 0; x--) {
char tmp = string[x];
line[i] = tmp;
i++;
}
for(x = 0; x < strlen(string); x++)
{
string[x] = line[x];
}
}
Note that this function will cause an apocalypse when passed an empty string or a string literal (as Bobby Sacamano said).
Suggestion you can probably do: void reverse(char source[], char[] dest) and do checks if the source string is empty.
I think that your answer is almost correct. You don't actually need an extra slot for the null character in line. You just need two minor changes:
Change the assignment statement at the bottom of the procedure to a memcpy.
Change the loop condition to <-
So, your correct code is this:
void reverse (char string[]) {
int x;
int i = 0;
char line[strlen(string)];
for (x = strlen(string) - 1; x >= 0; x--) {
char tmp = string[x];
line[i] = tmp;
i++;
}
memcpy(string, line, sizeof(char) * strlen(line));
}
Since you want to reverse a string, you first must decide whether you want to reverse a copy of the string, or reverse the string in-situ (in place). Since you asked about this in 'C' context, assume you mean to change the existing string (reverse the existing string) and make a copy of the string in the calling function if you want to preserve the original.
You will need the string library
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Array indexing works, and this version takes that approach,
/* this first version uses array indexing */
char*
streverse_a(char string[])
{
int len; /*how big is your string*/
int ndx; /*because 'i' is hard to search for*/
char tmp; /*hold character to swap*/
if(!string) return(string); /*avoid NULL*/
if( (len=strlen(string)) < 2 ) return(string); /*one and done*/
for( ndx=0; ndx<len/2; ndx++ ) {
tmp=string[ndx];
string[ndx]=string[len-1-ndx];
string[len-1-ndx]=tmp;
}
return(string);
}
But you can do the same with pointers,
/* this is how K&R would write the function with pointers */
char*
streverse(char* sp)
{
int len, ndx; /*how big is your string */
char tmp, *bp, *ep; /*pointers to begin/end, swap temporary*/
if(!sp) return(sp); /*avoid NULL*/
if( (len=strlen(bp=sp)) < 2 ) return(sp); /*one and done*/
for( ep=bp+len-1; bp<ep; bp++, ep-- ) {
tmp=*bp; *bp=*ep; *ep=tmp; /*swap*/
}
return(sp);
}
(No, really, the compiler does not charge less for returning void.)
And because you always test your code,
char s[][100] = {
"", "A", "AB", "ABC", "ABCD", "ABCDE",
"hello, world", "goodbye, cruel world", "pwnz0r3d", "enough"
};
int
main()
{
/* suppose your string is declared as 'a' */
char a[100];
strcpy(a,"reverse string");
/*make a copy of 'a', declared the same as a[]*/
char b[100];
strcpy(b,a);
streverse_a(b);
printf("a:%s, r:%s\n",a,b);
/*duplicate 'a'*/
char *rp = strdup(a);
streverse(rp);
printf("a:%s, r:%s\n",a,rp);
free(rp);
int ndx;
for( ndx=0; ndx<10; ++ndx ) {
/*make a copy of 's', declared the same as s[]*/
char b[100];
strcpy(b,s[ndx]);
streverse_a(b);
printf("s:%s, r:%s\n",s[ndx],b);
/*duplicate 's'*/
char *rp = strdup(s[ndx]);
streverse(rp);
printf("s:%s, r:%s\n",s[ndx],rp);
free(rp);
}
}
The last line in your code does nothing
string = line;
Parameters are passed by value, so if you change their value, that is only local to the function. Pointers are the value of the address of memory they are pointing to. If you want to modify the pointer that the function was passed, you need to take a pointer to that pointer.
Here is a short example of how you could do that.
void reverse (char **string) {
char line = malloc(strlen(*string) + 1);
//automatic arrays are deallocated once the function ends
//so line needs to be dynamically or statically allocated
// do something to line
*string = line;
}
The obvious issue with this is that you can initialize the string with static memory, then this method will replace the static memory with dynamic memory, and then you'll have to free the dynamic memory. There's nothing functionally wrong with that, it's just a bit dangerous, since accidentally freeing the string literal is illegal.
char *test = "hello";
reverse(test);
free(test); //this is pretty scary
Also, if test was allocated as dynamic memory, the pointer to it would be lost and then it would become a memory leak.

Resources