Head First C string.h related questions - c

#include <stdio.h>
#include <string.h>
void print_reverse(char *s)
{
size_t len = strlen(s);
char *t = s + len - 1;
while (t >= s)
{
printf("%c", *t);
t = t - 1;
}
puts("");
}
Above is a function that will display a string backward on the screen. But I don't understand the 7th line (char *t = s+ len-1;). Could anybody explain this is spoken English please?

For starters this function
void print_reverse(char *s)
{
size_t len = strlen(s);
char *t = s + len - 1;
while (t >= s)
{
printf("%c", *t);
t = t - 1;
}
puts("");
}
is wrong and has undefined behavior.:)
There are two problems.
The first one is that the passed string as the argument can have a zero-length. In this case this declaration
char *t = s + len - 1;
will look like
char *t = s - 1;
and the pointer t can be wrong.
The second problem is that this expression statement
t = t - 1;
has undefined behavior in case when the pointer t is equal to s.
From the C Standard (6.5.6 Additive operators)
...If both the pointer operand and the result point to elements of the same
array object, or one past the last element of the array
object, the evaluation shall not produce an overflow; otherwise, the
behavior is undefined.
A correct function implementation can look the following way
void print_reverse( const char *s)
^^^^^
{
size_t len = strlen(s);
const char *t = s + len;
^^^^^^^
while (t != s)
^^^^^^
{
printf("%c", *--t);
^^^^
}
puts("");
}
As for your question then in this declaration
char *t = s + len - 1;
the pointer t is tried to be initialized by the address of the last character of the string before the terminating zero.

Main logic behind this functions is that this code:
char *t = s+ len-1;
return a pointer to the address of the last char in the char pointer you are passing to the function. The loop prints it by decrementing it:
t = t - 1;
So in simple words it prints the char pointer from backwards.

Related

C segfault when modifiy array value [duplicate]

This question already has answers here:
Modify the content of char* str
(2 answers)
Closed 10 months ago.
Im getting a segfault when changing dna[i] to U, Ive debbuged but I still cant understand why.
Also I was comparing the value at a position against T with strcmp, but from what I understand thats for string literals and I can simply compare it with dna[i] == 'T'. Is that right? thanks.
#include <string.h>
char *dna_to_rna(char *dna) {
int size = (int)( sizeof(dna) / sizeof(dna[0]));
char *retour[size];
strcpy(retour, dna);
for (int i = 0; i < size; i++) {
if (dna[i] == 'T') {
dna[i] = 'U';
}
}
return (char *) retour;
}
int main() {
char *dna[] = {
"TTTT",
"GCAT",
"GACCGCCGCC"
};
char *actual, *expected;
size_t n;
for (n = 0; n < 3; ++n) {
actual = dna_to_rna(*(dna + n));
}
return 0;
}
You are passing to the function dna_to_rna a pointer to a string literal
actual = dna_to_rna(*(dna + n));
and then within the function you are trying to change the string literal
if (dna[i] == 'T') {
dna[i] = 'U';
}
Any attempt to change a string literal results in undefined behavior.
Also the expression with the sizeof operator in this declaration
int size = (int)( sizeof(dna) / sizeof(dna[0]));
does not make a sense. It evaluates the size of a pointer of the type char *.
Instead you should use the standard string function strlen.
And this declaration is incorrect
char *retour[size];
At least you need a character array instead of an array of pointers.
char retour[size];
And the function returns a pointer to an array with automatic storage duration that will not be alive after exiting the function
char *dna_to_rna(char *dna) {
//...
char retour[size];
//...
return (char *) retour;
}
that is the function returns an invalid pointer.
You should dynamically allocate a character array within the function with the length strlen( dna ) + 1 and change and return this array.
It seems what you mean is something like the following
#include <string.h>
#include <stdlib.h>
char * dna_to_rna( const char *dna )
{
size_t n = strlen( dna );
char *retour = malloc( n + 1 );
if ( retour != NULL )
{
strcpy( retour, dna );
for ( size_t i = 0; i < n; i++ )
{
if ( retour[i] == 'T' ) retour[i] = 'U';
}
}
return retour;
}

REVERSE_WORD in c using pointers

i have try this code made by me but no output and there's no errors?
#include <stdio.h>
void reverse(char *p,char *v,int size){
for(int i=size-1,j=0;i<0;i--){
*(v+j) = *(p+i);
j++;
}
}
int main(){
char word[6] = {"hello"};
char re_word[6];
re_word[5]='\0';
reverse(word,re_word,6);
printf("%s",re_word);
}
Using pointers it can look like this:
void reverse(char *w, char *revw, int slen) {
revw += slen - 1; // forward to pos. of last letter
revw[1] = '\0'; // one further *(revw+1)
while (*w)
*revw-- = *w++;
}
This is clear and symmetric, once it works, while your i-- and j++ are far apart.
slen is meant to be the number of letters w/o termination. Here the call:
char word[] = {"hello"};
char re_word[sizeof word];
reverse(word, re_word, sizeof word - 1);
strlen() should be used, probably, but these lines show how you can and have to control not just the total size but especially the last byte of the char array.
Without the correct length, reverse() would have to do a strlen() first, because it has to know how far away to put the first letter.
This *(v+j) = *(p+i) is more or less v[j] = p[i] and does not really take advantage of pointers, on the contrary.
(revw
caller) in reverse()
| |
v v
-4 -3 -2 -1 revw +1
o l l e h \0
... revw-- revw[1]
So revw is maybe not the best name inside the function; revw_first_backwards is meant...or fill_start. But before I fill backwards I do the one additional write to the right side to terminate the string: array notation using a pointer: revw[1] = '\0'.
First of all, i < 0 will always be false, given i = size - 1 > 0.
What you want is i >= 0.
Also, given size = 6, size - 1 will be equal to 5, and that is the NULL terminator position since array indexing in C start from 0. Perhaps use a C function such as strlen() to calculate the length rather than hard coding it.
void reverse(char *p, char *v, size_t size)
{
for (int i = size - 1, j = 0; i >= 0; i--)
{
*(v + j) = *(p + i);
j++;
}
}
int main()
{
char word[6] = {"hello"};
char re_word[6];
re_word[5] = '\0';
reverse(word, re_word, 5); /* or reverse(word, re_word, strlen(word)) */
printf("%s", re_word);
}

Getting garbage after reversing string in c

I am trying to reverse a string. scanf is working well but when I use fixed string then it gives garbage value. So where is the fault ?
#include<stdio.h>
#include<string.h>
int main()
{
char s[50]="Hi I Love Programming";
char rev[strlen(s)];
int i,k;
k=strlen(s);
for(i=0; i<strlen(s); i++)
{
rev[k]=s[i];
k--;
}
printf("The reverse string is: %s\n", rev);
}
Your program has two issues:
1.
char rev[strlen(s)];
You forgot to add an element for the string-terminating null character '\0'.
Use:
char rev[strlen(s) + 1];
Furthermore you also forgot to append this character at the end of the reversed string.
Use:
size_t len = strlen(s);
rev[len] = '\0';
Note, my len is the k in your provided code. I use the identifier len because it is more obvious what the intention of that object is. You can use strlen(s) because the string has the same length, doesn´t matter if it is in proper or reversed direction.
2.
k=strlen(s);
for(i=0; i<strlen(s); i++)
{
rev[k]=s[i];
k--;
}
With rev[k] you accessing memory beyond the array rev, since index counting starts at 0, not 1. Thus, the behavior is undefined.
k needs to be strlen(s) - 1.
Three things to note:
The return value of strlen() is of type size_t, so an object of type size_t is appropriate to store the string length, not int.
It is more efficient to rather calculate the string length once, not at each condition test. Use a second object to store the string length and use this object in the condition of the for loop, like i < len2.
char s[50]="Hi I Love Programming"; can be simplified to char s[]="Hi I Love Programming"; - The compiler automatically detects the amount of elements needed to store the string + the terminating null character. This safes unnecessary memory space, but also ensures that the allocated space is sufficient to hold the string with the null character.
The code can also be simplified (Online example):
#include <stdio.h>
#include <string.h>
int main(void)
{
char s[] = "Hi I Love Programming";
size_t len = strlen(s);
char rev[len + 1];
size_t i,j;
for(i = 0, j = (len - 1); i < len; i++, j--)
{
rev[j] = s[i];
}
rev[len] = '\0';
printf("The reverse string is: %s\n", rev);
}
Output:
The reverse string is: pgnimmargorP evoL I iH
your program is hard to understand. Here you have something much simpler (if you want to reverse the string of course)
#include <stdio.h>
#include <string.h>
char *revstr(char *str)
{
char *start = str;
char *end;
if(str && *str)
{
end = str + strlen(str) - 1;
while(start < end)
{
char tmp = *end;
*end-- = *start;
*start++ = tmp;
}
}
return str;
}
int main()
{
char s[50]="Hi I Love Programming";
printf("%s", revstr(s));
}
https://godbolt.org/z/5KX3kP

How do you modify a string in C

I'm new to C and I'm attempting to perform a modification to a string that I have (I'm attempting to reverse it), but I'm unsure why the program doesn't run as intended (displays no output).
void reverse(char *rTarget);
int main()
{
char memes[] = "memes";
reverse(memes);
printf("%s", memes);
}
void reverse(char *rTarget)
{
char swap;
int length = (int) strlen(rTarget);
for (int i = 0; i < length / 2; i++)
{
swap = rTarget[i];
rTarget[i] = rTarget[length - i];
rTarget[length - i] = swap;
}
}
For starters this function declaration
void reverse(char *rTarget[]);
is equivalent to
void reverse(char **rTarget);
There is no great sense to declare it such a way.
You should declare the function like
void reverse( char rTarget[] );
and call it like
reverse( memes );
The function definition is also wrong. At least you have to use the loop like
for (int i = 0; i < length / 2; i++)
and these expressions
swap = *rTarget[i];
*rTarget[i] = *rTarget[length - i];
*rTarget[length - i] = swap;
are invalid. They shall be rewritten like
swap = ( *rTarget )[i];
( *rTarget )[i] = ( *rTarget )[length - i -1];
( *rTarget )[length - i - 1] = swap;
Also the variable length shall have the type size_t because in general an object of the type int can not accommodate an object of the type size_t and the function strlen have the return type size_t. So you have to substitute this declaration
int length = (int) strlen(*rTarget);
For this declaratiuon
size_t length = strlen(*rTarget);
Pay attention to that according to the conventions for standard C string functions the function should return pointer to the reversed string.
And according to the C Standard the function main without parameters shall be declared like
int main( void )
Here is a demonstration program that shows how the function can be declared and defined
#include <stdio.h>
#include <string.h>
char * reverse( char *s )
{
for ( size_t i = 0, n = strlen( s ); i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n-i-1];
s[n-i-1] = c;
}
return s;
}
int main(void)
{
char memes[] = "memes";
puts( reverse( memes ) );
return 0;
}
The program output is
semem
#include <stdio.h>
#include <string.h>
void reverse(char *rTarget);
int main()
{
char memes[] = "memes";
reverse(memes);
printf("%s", memes);
}
void reverse(char *rTarget)
{
int length = (int) strlen(rTarget);
for (int i = 0; i < length / 2; i++)
{
char swap = rTarget[i];
rTarget[i] = rTarget[length - i - 1];
rTarget[length - i - 1] = swap;
}
}
The expression *rTarget[i] is parsed as *(rTarget + i), not *(rTarget) + i as you may expect. And you do not need to pass char ** here.
The problem is here
*rTarget[i] = *rTarget[length - i]
*rTarget[length - i] = swap;
The primary problem seems to be operator precedence. [] has higher precedence than *. You are passing "array of strings" (because pointers can be used as arrays), so when i is 0, on the left side you take the first (and only existing) array at [0], and * references its first character. To this you assign nonsense from the right side: first character of array [length] (which doesn't exist), which is undefined behavior, so what you program does after this is meaningless to speculate about. You need to add parentheses, so that you reference the pointer to array, so you get the actual array, and then use [] on that.
But even if you add parentheses, your algorithm is wrong. On first round, i is 0 so you copy (*rTarget)[length] to start of string. That is the string terminating 0, so you end up with modified string length 0 (first byte is 0). You need -1 for the length.
Fixing your original code, it therefore becomes:
for (int i = 0; i < length / 2; i++)
{
swap = (*rTarget)[i];
(*rTarget)[i] = (*rTarget)[length - i - 1];
(*rTarget)[length - i - 1] = swap;
}
Additionally, your function argument is needlessly complex (pointer to pointer to char), straight pointer to modifiable string is enough. Other answers cover that beauty issue.
There are all kinds of dereferencing errors here. Rememember, a string is an array of characters, not an array of character pointers. So this
void reverse(char *rTarget[])
Should be
void reverse(char rTarget[])
And here:
int length = (int) strlen(*rTarget);
You don't have to dereference rTarget, so remove the *. Same in the swap, remove all * that you have there.
Last but not least, there's an off by one error in your swap. Instead of going to length - i, you want to go to length - i - 1, otherwise you're swapping the null terminator to the beginning.
Also your loop should only go to the first half of the array, because otherwise you swap everything twice, resulting in the original string again:
for (int i = 0; i < length/2; i++)
All in all it should look like this:
void reverse(char rTarget[]);
int main()
{
char memes[] = "memes";
reverse(memes);
printf("%s", memes);
}
void reverse(char rTarget[])
{
char swap;
int length = (int)strlen(rTarget);
for (int i = 0; i < length/2; i++)
{
swap = rTarget[i];
rTarget[i] = rTarget[length - i - 1];
rTarget[length - i - 1] = swap;
}
}
This should do it:
void reverse(char rTarget[]);
int main()
{
char memes[] = "memes";
reverse(memes);
printf("%s", memes);
}
void reverse(char rTarget[])
{
char swap;
int lastindex = (int) strlen(rTarget) - 1;
for (int i = 0; i < lastindex / 2; i++)
{
swap = rTarget[i];
rTarget[i] = rTarget[lastindex - i];
rTarget[lastindex - i] = swap;
}
}
There are a couple of problems in your code.
First of all, arrays are always 'passed by reference', so you don't need to pass a pointer to an array. Any changes you make in the array will persist after the function call.
Secondly, array subscripts in C start from 0. So the last character (not counting null) in a string of length n is string[n-1] not string[n].
EDIT: As #roottraveller mentioned, since you are swapping characters, you don't need to run till the end of the string. You only need to go till the half of length.
If you are not intended to send multiple strings to reverse function then function argument only require a char pointer. While swap character you need to traverse only 50% of the string. The code can be as following.
void reverse(char *rTarget)
{
char swap;
int length = (int) strlen(rTarget);
for(int i = 0, j = (length - 1); i < (length / 2); i++, j--)
{
swap = *(rTarget+i);
*(rTarget+i) = *(rTarget+j);
*(rTarget+j) = swap;
}
}

Can anyone explain to me this piece of code? I am new to C

I am trying to learn C, so I went to try out some of the coderbyte challenges in C, one of which is to reverse a string. After gettung multiple compilation errors due to syntax I tried looking for examples and encountered this one on http://www.programmingsimplified.com/c-program-reverse-string
#include<stdio.h>
int string_length(char*);
void reverse(char*);
main()
{
char string[100];
printf("Enter a string\n");
gets(string);
reverse(string);
printf("Reverse of entered string is \"%s\".\n", string);
return 0;
}
void reverse(char *string)
{
int length, c;
char *begin, *end, temp;
length = string_length(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--;
}
}
int string_length(char *pointer)
{
int c = 0;
while( *(pointer + c) != '\0' )//I DON'T UNDERSTAND THIS PART!!!!!
c++;
return c;
}
c is not even a char, so why would you add it? Or is pointer some sort of index considering the context of the while loop?
The + operator here does not mean string concatenation; it means pointer arithmetic. pointer is a pointer to a char, and c is an int, so pointer + c results in a pointer to a char that is c chars further forward in memory. For example, if you have an array {'j', 'k', 'l', 'm'} and pointer pointed at the 'j', and c was 2, then pointer + c would point at the 'l'. If you advance a pointer like this then deference it, that acts the same as the array indexing syntax: pointer[c]. The loop is therefore equivalent to:
while( pointer[c] != '\0' )
c++;
The effect of adding a pointer to an integer (or vice-versa) scales according to the size of what the pointer is (supposedly) pointing to, so you don't need to account for different sizes of objects. foo + 5, if foo is a pointer, will go 5 objects further forward in memory, whatever size object foo points to (assuming that foo is pointing at the type it is declared to point to).
Here you can talk about pointer arithmetic.
There is an important concept :
Addition a integer to a pointer will move the pointer forward. The number that you are adding will be multiplied by the size of type that the pointer is pointing to.
Example :
An int is coded on 4 bytes, so when we increment the pointer by 1, we have to multiply by 4 to obtain what really happen in regular arithmetic.
int a[3] = {1, 3, 6};
printf("%d\n", *(a + 1)); // print 3, look 4 bytes ahead
printf("%d \n", *(a + 2)); //print 6, look 8 bytes ahead
In your case :
A char is coded on 1 byte so
*(pointer + c) with c == 3
will evaluate to a memory address of 3 bytes (3 chars) ahead.
So the code :
while( *(pointer + c) != '\0' )
c++;
will evaluate the value of your pointer at a specific memory address. If the character is equal to the null-character, we have reached the end of the string.
Remember that *(pointer + c) is equivalent to pointer[c].
c is being used as an index.
/* reverse: Reverses the string pointed to by `string` */
void reverse(char *string)
{
int length, c;
char *begin, *end, temp;
/* compute length of string, initialize pointers */
length = string_length(string);
begin = string; /* points to the beginning of string */
end = string; /* will later point to the end of string */
/* make end point to the end */
for (c = 0; c < length - 1; c++)
end++;
/* walk through half of the string */
for (c = 0; c < length/2; c++)
{
/* swap the begin and end pointers */
temp = *end;
*end = *begin;
*begin = temp;
/* advance pointers */
begin++;
end--;
}
}
/* computes length of pointer */
int string_length(char *pointer)
{
int c = 0;
/* while we walk `pointer` and we don't see the null terminator */
while( *(pointer + c) != '\0' )//I DON'T UNDERSTAND THIS PART!!!!!
c++; /* advance position, c */
/* return the length */
return c;
}
The string_length function can be rewritten as
size_t strlen(const char *str)
{
size_t i;
for (i = 0; *str; ++i)
;
return i;
}
From what I understand if the string is : abcd
the result would be : dcba
if the input is : HELLO-WORLD
the output would be : DLROW-OLLEH

Resources