I tried following two ways to reverse a string in C using char pointers:
Option 1:
void stringreverse(char *s){
int n = stringlength(s) - 2;
while(*s != '\0'){
char c = *s;
*s = *(s+n);
*(s+n) = c;
s++;n--;
}
}
Option 2:
void stringreverse(char *s){
char *p = s + stringlength(s) - 2;
while(*s != '\0'){
char c = *s;
*s = *p;
*p = c;
s++,p--;
}
}
None of the above works. Hints on why?
The problem is that your code reverses the string and then reverse it again, because your loop goes from 0 to len (when *s==\0), it should stop at (len-1)/2
You should try this :
void stringreverse(char* s){
int len = strlen(s)-1;
int i;
for(i=0;i<len/2;i++){
char tmp = s[i];
s[i] = s[len-i];
s[len-i]=tmp;
}
}
To reverse the string you should swap the chars between the beginning and the end of the string until they meet in the middle, the way you did will reverse it and then reverse it again to the original string. Also there is strlen in standard C. Anyway using your definition of stringlength, it should be:
void stringreverse(char *s){
int n = stringlength(s) - 2;
int i;
while(i = 0; i < n / 2; i++) {
char c = s[i];
s[i] = s[n-i];
s[n-i] = c;
}
}
complete working sample using pointers:
#include <stdio.h>
void reverse(char *p){
char c;
char* q = p;
while (*q) q++;
q--; // point to the end
while (p < q){
c = *p;
*p++ = *q;
*q-- = c;
}
}
int main(){
char s[] = "DCBA";
reverse(s);
printf("%s\n", s); // ABCD
}
p: points to start of string.
q: points to the end of string.
then swap their contents.
simple and easy.
Related
I'm trying to solve a piece of code a friend sent me. He's practicing pointers and is trying to reverse a string using them.
It should be a pretty simple task, but there's just a gap in my knowledge here. I've been able to successfully create a for loops which iterates through the string properly using i and j as control variables. I've been able to print out the characters as well, which need to be swapped.
The only problem is that commented line of code in the for loop. It's supposed to be swapping the two values, but is throwing an error, and I don't get why.
#include <stdio.h>
int length(char *p);
void reverse(char *);
int main() {
char *p = "Computer";
reverse(p);
}
int length(char *p) {
int i;
for (i = 0; *(p + i) != '\0'; i++);
return i;
}
void reverse(char *p) {
int l, i;
char t;
for (l = 0; *(p + l) != '\0'; l++);
int len = l;
int temp;
for (i = 0; i < l; i++, l--) {
t = *(p + i);
printf("i-th element - %c\n", t);
printf("j-th element - %c\n", *(p + len - 1 - i));
*(p + i) = *(p + len - 1 - i); // crash
}
puts(p);
}
I'm not even sure it's possible to swap them this way. I would have gone with the t = p[i]; p[i] = p[i + 1]... approach. If anyone can correct and explain this and the pointer related drama, that would be great.
Firstly, you must not try to modify string literals.
You should use an (modifiable) array:
char p[] = "Computer";
instead of
char *p = "Computer";
Secondly, you will need
*(p + len - 1 - i) = t;
after
*(p + i) = *(p + len - 1 - i);
to complete the swapping.
For starters you may not change a string literal
char *p = "Computer";
any attempt to change a string literal result in undefined behavior.
So instead of the pointer to a string literal declare a character array like
char s[] = "Computer";
Moreover your function reverse does not use the function length and in fact does not reverse a string.
This loop
for (i = 0; i < l; i++, l--) {
uses two auxiliary variables as indices.
The function reverse shall output nothing. What it shall do is one thing to reverse the passed string. It is the caller of the function that decides whether to output the reversed string or to use it for other purposes.
The functions length and reverse can be declared and defined using only pointers the following way
size_t length( const char *s )
{
const char *p = s;
while ( *p ) ++p;
return p - s;
}
and
char * reverse( char *s )
{
if ( *s )
{
for ( char *p = s, *q = s + length( s ); p < --q; ++p )
{
char c = *p;
*p = *q;
*q = c;
}
}
return s;
}
The function reverse can be called like
int main( void )
{
char s[] = "Computer";
puts( s );
puts( reverse( s ) );
}
Here is a demonstrative program.
#include <stdio.h>
size_t length( const char *s )
{
const char *p = s;
while ( *p ) ++p;
return p - s;
}
char * reverse( char *s )
{
if ( *s )
{
for ( char *p = s, *q = s + length( s ); p < --q; ++p )
{
char c = *p;
*p = *q;
*q = c;
}
}
return s;
}
int main( void )
{
char s[] = "Computer";
puts( s );
puts( reverse( s ) );
}
Its output is
Computer
retupmoC
As you can see in the both functions neither variable used as an index is present. The functions use only pointers.
Using pointes requires some care otherwise you'll get "Segmentation fault" everywhere. But let's do this. A technique to reverse the string I use, is first position one ponter to the beginning of string, and another pointer to the end of string; and promote the swap while they reach the middle of string (this way I cut the processing to a half) check this code
/* reverses a string
* !!! this function modifies input string !!!
*/
char *reverse(char *s)
{
char *h, *t, c; /* h)ead, t)ail and a temporary c */
int len = 0;
/* positioning the pointers at beginning and end of string s */
len = length(s);
h = (char*)&s[0];
t = (char*)&s[len - 1];
for (int i = 0; i < (len / 2); i++)
{
/* swap chars */
c = *h;
*h = *t;
*t = c;
/* increase h pointer, decrease t pointer */
h++;
t--;
}
return s;
}
Pure pointers... in anyform when swapping the *h and *t you can't get away from a temporary storage ( c );
Be aware the input string needs to be declared as char name[] otherwhise sigsegv follows you!
If you want to save the string for later vice printing it directly to stdout, you can do this:
char * reverse(char * I){
int i,l;
char * O;
l=strlen(I);
O=malloc(l+1);
for(i=1;i<=l;i++)O[i-1]=I[l-i];
O[l]='\0';
return O;
}
int main(){
char * p=reverse("Computer");
printf("%s",p);
free(p);
}
I am playing with pointers in the K&R book and I wrote this program that swaps integers and measures the length of a string with a pointer. The first part works but my string length function does nothing. The program compiles and runs the first part and then the program stops responding.
#include <stdio.h>
extern int a2 = 4;
extern int b2 = 5;
void swap(int *px, int *py);
int strlen2(char *s);
//int printLabel(char *thelabel, char newliner);
//int printLabel(char *thelabel, char newliner)
//{
// int stringlength1=(strlen2(thelabel));
// return stringlength1;
//}
void swap(int *px, int *py) /* interchange *px and *py */
{
int temp;
temp = *px;
*px = *py;
*py = temp;
}
int strlen2(char *s)
{
int n;
for (n = 0; *s != '\0', s++;)
n++;
return n;
}
int main()
{
int a=4;
int b=5;
char newliner = '\n';
swap(&a,&b);
swap(&a2,&b2);
printf("%d",a);
printf("%c",newliner);
printf("%d",b);
printf("%c",newliner);
printf("%d",a2);
printf("%c",newliner);
printf("%d",b2);
printf("%c",newliner);
char sumstring[]="boo";
char *labelPtr;
labelPtr = sumstring;
int length = strlen2(labelPtr);
printf("%d",length);
return 0;
}
The problem is that this:
for (n = 0; *s != '\0', s++;)
is a semi-infinite loop. It checks for the terminating NUL, but then it ignores the result of that comparison and increements s, continuing the loop if it is non-null. Once it gets past the end of the string, the result is undefined behavior, but its likely to either loop forever or crash.
You probably meant
for (n = 0; *s != '\0'; s++)
In the for loop, the second expression is usually a condition, in your case *s != '\0'.
The 3rd expression is the increment, where you are supposed to increment the s pointer.
This is working fine:
int strlen2(char *s)
{
int n;
for (n = 0; *s != '\0'; s++)
n++;
return n;
}
Replace your code with the following:
int strlen2(char *s)
{
int n = 0;
while(s[n] != '\0')
++n;
return n;
}
looks like a typo in the code. shouldn't this line be:
for (n = 0; *s != '\0'; s++)
instead of
for (n = 0; *s != '\0', s++;)
In this for statmenet
for (n = 0; *s != '\0', s++;)
in the condition part there is used the comma operator
*s != '\0', s++
Its results is the value of the last subexpression that is of s++. As pointer s is not equal to 0 then you get at least very long sycle.
I think you meant instead
for (n = 0; *s != '\0'; s++ )
I wrote the following function to inverse a string s
char *strinverse( const char *s ){
char *t;
int i = 0;
while (*s) {
s++;
i++;
}
while (i >= 0){
s--;
*t = *s;
t++;
i--;
}
*t = '\0';
return t;
}
int main(void){
char v[4]="abc";
char r[4];
char *pr = r;
pr = strinverse(v);
printf("%s", pr);
return 0;
}
The idea is to find out the length of the string s in the first while-loop, then to decrease the pointer of s while copying the respective values into t. For some reason the program crashes and the compiler gives me no information. Maybe there's something wrong in the main function? Thanks for your advices!
Answer edited
#include<stdio.h>
#include<stdlib.h>
char *strinverse(const char *s ){
char *t, *p;
int i = 0;
while (*s) {
s++;
i++;
}
t = (char*)malloc((i + 1) * sizeof(char)); //added this!
p = t;
while (i >= 0){
s--;
*t = *s;
t++;
i--;
}
*t = '\0';
return p;
}
int main(void){
char v[4]="abc";
char *pr;
pr = strinverse(v);
printf("%s\n", pr);
return 0;
}
The reason that program crashes is that you have not allocated space for pointer t. In this case your program invokes undefined behavior. Allocate space for t
t = malloc(i + 1);
Do not forget to free memory at the end using free(t).
I would use a function that changes the string in-place instead.
void reversestr(char *s)
{
char tmp;
size_t i, len = strlen(s);
for (i = 0; i < len / 2; i++) {
tmp = s[i];
s[i] = s[len - 1 - i];
s[len - 1 - i] = tmp;
}
s[len] = '\0';
}
If you need the reversed string separately, you can just use strdup before you call reversestr. BTW: function names that start with "str" are reserved for functions of the C standard library.
you have not make malloc in the pointer "t" and you have problem in this line "*t = *s;"
I am new with pointers on C and I am trying to write a function like strcat() but without using it. I developed the following function:
char cat(char *a, char *b) {
int i=0,cont=0,h=strlen(a)+strlen(b);
char c[h]; //new string containing the 2 strings (a and b)
for(i;i<strlen(a);++i) {
c[i] = *(a+i); //now c contains a
}
int j = i;
for(j;j<strlen(b);++j) {
c[j] = *(b+cont); //now c contains a + b
cont++;
}
return c; // I return c
}
And this is how I call the function:
printf("\Concatenazione: %c", cat(A,B));
It is now working because the final result is a weird character. How could I fix the function? Here there's the full main.
char * strcat(char *dest, const char *src)
{
int i;
int j;
for (i = 0; dest[i] != '\0'; i++);
for (j = 0; src[j] != '\0'; j++) {
dest[i+j] = src[j];
}
dest[i+j] = '\0';
return dest;
}
From your implementation it appears that your version of strcat is not compatible with the standard one, because you are looking to allocate memory for the result, rather than expecting the caller to provide you with enough memory to fit the result of concatenation.
There are several issues with your code:
You need to return char*, not char
You need to allocate memory dynamically with malloc; you cannot return a locally allocated array.
You need to add 1 for the null terminator
You need to write the null terminator into the result
You can take both parameters as const char*
You can simplify your function by using pointers instead of indexes, but that part is optional.
Here is how you can do the fixes:
char *cat(const char *a, const char *b) {
int i=0,cont=0,h=strlen(a)+strlen(b);
char *c = malloc(h+1);
// your implementation goes here
c[cont] = '\0';
return c;
}
You are returning a POINTER to the string, not the actual string itself. You need to change the return type to something like "char *" (or something equivalent). You also need to make sure to null terminate the string (append a '\0') for it to print correctly.
Taking my own advice (and also finding the other bug, which is the fact that the second for loop isn't looping over the correct indices), you end up with the following program:
#include <stdio.h>
char *cat(char *a, char *b) {
int i = 0, j = 0;
int cont = 0;
int h = strlen(a) + strlen(b) + 1;
char *result = (char*)malloc(h * sizeof(char));
for(i = 0; i < strlen(a); i++) {
result[i] = a[i];
}
for(j = i; j < strlen(b)+ strlen(a); j++) {
result[j] = b[cont++];
}
// append null character
result[h - 1] = '\0';
return result;
}
int main() {
const char *firstString = "Test First String. ";
const char *secondString = "Another String Here.";
char *combined = cat(firstString, secondString);
printf("%s", combined);
free(combined);
return 0;
}
c is a local variable. It only exists inside the function cat. You should use malloc.
instead of
char c[h];
use
char *c = malloc(h);
Also, you should add the null byte at the end. Remember, the strings in C are null-ended.
h = strlen(a) + strlen(b) + 1;
and at the end:
c[h - 1] = '\0';
The signature of cat should be char *cat(char *a, char *b);
You will get an error of
expected constant expression
for the code line char c[h];. Instead you should be using malloc to allocate any dynamic memory at run-time like::
char* c ;
c = malloc( h + 1 ) ; // +1 for the terminating null char
// do stuff
free( c ) ;
Your corrected code::
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include <stdlib.h>
char* cat(char *a, char *b) {
int i=0,cont=0,h=strlen(a)+strlen(b), j;
char *c;
c = malloc( h+1 ) ;
for(i;i<strlen(a);++i) {
c[i] = *(a+i);
}
j = 0 ;
for(j;j<strlen(b);++j) {
c[i] = *(b+cont);
i++ ;
cont++;
}
c[i] = 0 ;
return c;
}
int main() {
char A[1000],B[1000];
char * a ;
printf("Inserisci la stringa 1: \n");
gets(A);
printf("Inserisci la stringa 2: \n");
gets(B);
a = cat(A,B) ;
printf("\nConcatenazione: %s", a);
free(a) ;
getch();
return 0;
}
I have just written a program which reverses a sentence whatever the user gives. For example: if the user enters "How are you", my program generates "uoy era woH".
The programme which I wrote is shown below. I just have a wild intution that there can be a smarter program than this. So valuable input from your side is most appreciated or any better program than this is also most welcome.
int ReverseString(char *);
main() {
char *Str;
printf("enter any string\n");
gets(Str);
ReverseString(Str);
getch();
}
int ReverseString(char *rev) {
int len = 0;
char p;
while(*rev!='\0') {
len++;
rev++;
}
rev--;
while(len>0) {
p = *rev;
putchar(p);
rev--;
len--;
}
}
Thanks a lot.
You could use recursion.
int ReverseString(char *rev) {
if(*rev!='\0') {
ReverseString(rev + 1);
putchar(*rev);
}
return 1;
}
void ReverseString( char* str, int len ) {
if( len > 1 ) {
swap( &str[0], &str[len - 1] );
ReverseString( ++str, len - 2 );
}
}
Or, unrolling the tail-recursion:
void ReverseString( char* str, int len ) {
while( len > 1 ) {
swap( &str[0], &str[len - 1] );
++str;
len -= 2;
}
}
Where swap is defined as:
void swap( char* a, char* b ) {
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
If you use this though, your TA's will definitely know you didn't figure this out yourself :)
Okay, here is my function. I wrote it a while ago, just for practice.
char* reverse(char *string){
int length = 0;
int half = 0;
length = strlen(string);
half = (length/2) - 1;
--length;
int i = 0;
register char interim;
for(; i<=half; ++i){
interim = string[i];
string[i] = string[length - i];
string[length - i] = interim;
}
return string;
}
now that I look at it, I'm less proud of it than when I got it to work. I'm just posting it because you asked me to post it when I found it--and for completeness' sake.
After looking at some other answers I realize that the calculation of half the string is unnecessary and I could have just decremented length until i and length were equal. Oh well--here it is.
Also, please don't bash me for the use of the register keyword :P
Yet another variation...
void ReverseString( char *str, int len ) {
int i;
for(i=0; i < len/2; i++) {
swap( &str[i], &str[len -1 -i] );
}
}
void swap( char *a, char *b ) {
char tmp = *a;
*a = *b;
*b = tmp;
}
void revstr(TCHAR *str) {
if( *str == '\0' ) {
return;
}
TCHAR *start = str;
TCHAR *end = start + strlen(str) - 1;
while(start < end) {
*start ^= *end;
*end ^= *start;
*start ^= *end;
*start++;
*end-–;
/*
could also use *start ^= *end ^= *start++ ^= *end–-; if you want to get fancy
*/
}
}
Stolen from the 2005 version of myself, but screw that guy, he slept with my wife. Yes, I know I don't need some of the '*'s, but I wrote the one-liner first and just converted it, and the one-liner does require them.
The following program prints its arguments in reverse character order:
#include <string.h>
#include <stdio.h>
char * reverse(char * string) {
char * a = string;
char * b = string + strlen(string) - 1;
for(; a < b; ++a, --b)
*a ^= *b, *b ^= *a, *a ^= *b; // swap *a <-> *b
return string;
}
int main(int argc, char * argv[]) {
for(int i = 1; i < argc; ++i)
puts(reverse(argv[i]));
}
Nothing new here, but IMO more readable than most other answers.
If you don't know the length of the string:
void reverse_string(char* str) {
char* p2 = str;
while (*p2 != '\0') {
/* assumes the string is null-terminated, will fail otherwise */
++p2;
}
--p2;
char* p1 = str;
while (p1 < p2) {
char tmp = *p1;
*p1 = *p2;
*p2 = tmp;
++p1;
--p2;
}
}
If you do:
void reverse_string(char* str, const size_t len) {
if (len <= 1) {
return;
}
char* p2 = str + len - 1;
char* p1 = str;
while (p1 < p2) {
char tmp = *p1;
*p1 = *p2;
*p2 = tmp;
++p1;
--p2;
}
}
This won't work. Should allocate memory for your sentence.
char *Str;
printf("enter any string\n");
gets(Str);
should be:
char str[81]={0};
printf("Enter any string up to 80 characters\n");
scanf("%80s\n",str);
ReverseString(str)
Besides, you should avoid gets function. It leads to buffer overflows
#include<stdio.h>
void reverse(char s[])
{
int i=0,j,x=0,z;
printf("\nThe string is : ");
printf("%s",s);
printf("\nThe reverse string is : ");
while(s[i] != ' ')
{
while(s[i] != ' ')
i++;
z=i+1;
for(j=i-1;j>=x;j--)
printf("%c",s[j]);
printf(" ");
i=z;
x=z;
}
}
main()
{
char s[50];
int a;
for(a=0;a<50;a++)
s[a]=' ';
puts("\nEnter a sentence : ");
fgets(s,50,stdin);
reverse(s);
}