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).
Related
I have two C-style strings:
char st[100] = "to be or not to be ";
char sub_s[100] = "be";
I need to find the beginning of the "be" with strstr(st, sub_s) and change it to capital letters. The new string needs to be `"to BE or not to BE ";
I manage to do it with out the function like so:
void main()
{
char st[100] = "to be or not to be ";
char sub_s[100] = "be";
char* p;
int i;
while (p = strstr(st, sub_s))
{
for (i = 0; i < strlen(sub_s); i++)
{
p[i] -= 32;
}
}
printf("%s\n", st);
}
But when I put this code into its own function it doesn't work any more:
void main()
{
char st[100] = "to be or not to be ";
char sub_s[100] = "be";
replaceSubstring(st, sub_s);
}
void replaceSubstring(char* str, char* substr)
{
int* p;
int i;
while (p = strstr(str, substr))
{
for (i = 0; i < strlen(substr); i++)
{
p[i] -= 32;
}
}
printf("%s\n", st);
}
What's going on here?
In the function that you've written, you've set the type of p to be an int*, not a char *. This means when you write
p[i] -= 32;
the compiler will assume each element pointed at by p is an int and therefore take a step of size sizeof(int) in memory rather than a step of size 1 in memory. In other words, the code is interpreted as
Start at the location pointed at by p.
Jump forward i * sizeof(int) bytes.
Read an integer value from that location.
Subtract 32 from it.
Write it back
rather than
Start at the location pointed at by p.
Find the character i steps down from there.
Subtract 32 from that character.
To fix this, change the type of p to be char*, not int*.
This is the sort of error that would likely be easily detected if you cranked the compiler warning level up to maximum. I would strongly recommend doing that when you're learning to code, then asking questions about the warnings you get when you don't understand them.
Some other stray notes:
The return type of main should be int, not void.
Rather than subtracting 32 from each character, which works but isn't the clearest thing in the word, consider using the tolower function from the <ctype.h> header.
If the substring you're searching for consists solely of non-letter characters (say, ":-)"), then this code can cause an infinite loop. Do you see why? Think about how you might fix it.
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.
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.
#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.
Language: C
I am trying to program a C function which uses the header char *strrev2(const char *string) as part of interview preparation, the closest (working) solution is below, however I would like an implementation which does not include malloc... Is this possible? As it returns a character meaning if I use malloc, a free would have to be used within another function.
char *strrev2(const char *string){
int l=strlen(string);
char *r=malloc(l+1);
for(int j=0;j<l;j++){
r[j] = string[l-j-1];
}
r[l] = '\0';
return r;
}
[EDIT] I have already written implementations using a buffer and without the char. Thanks tho!
No - you need a malloc.
Other options are:
Modify the string in-place, but since you have a const char * and you aren't allowed to change the function signature, this is not possible here.
Add a parameter so that the user provides a buffer into which the result is written, but again this is not possible without changing the signature (or using globals, which is a really bad idea).
You may do it this way and let the caller responsible for freeing the memory. Or you can allow the caller to pass in an allocated char buffer, thus the allocation and the free are all done by caller:
void strrev2(const char *string, char* output)
{
// place the reversed string onto 'output' here
}
For caller:
char buffer[100];
char *input = "Hello World";
strrev2(input, buffer);
// the reversed string now in buffer
You could use a static char[1024]; (1024 is an example size), store all strings used in this buffer and return the memory address which contains each string. The following code snippet may contain bugs but will probably give you the idea.
#include <stdio.h>
#include <string.h>
char* strrev2(const char* str)
{
static char buffer[1024];
static int last_access; //Points to leftmost available byte;
//Check if buffer has enough place to store the new string
if( strlen(str) <= (1024 - last_access) )
{
char* return_address = &(buffer[last_access]);
int i;
//FixMe - Make me faster
for( i = 0; i < strlen(str) ; ++i )
{
buffer[last_access++] = str[strlen(str) - 1 - i];
}
buffer[last_access] = 0;
++last_access;
return return_address;
}else
{
return 0;
}
}
int main()
{
char* test1 = "This is a test String";
char* test2 = "George!";
puts(strrev2(test1));
puts(strrev2(test2));
return 0 ;
}
reverse string in place
char *reverse (char *str)
{
register char c, *begin, *end;
begin = end = str;
while (*end != '\0') end ++;
while (begin < --end)
{
c = *begin;
*begin++ = *end;
*end = c;
}
return str;
}