How do you modify a string in C - 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;
}
}

Related

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);
}

GCC Compilation Error on array assignment

I am trying to convert a string into its equivalent matrix form in C. The matrix would have 3 rows and as many columns as required. The following code doesn't compile, and I haven't figured out what's going wrong.
The error that GCC throws is:
app.c:10:25: error: subscripted value is not an array, pointer, or vector
printf("%d\n", arr[i][k]);
~~~^~
1 error generated.
Main file (app.c):
#include <stdio.h>
#include "converter.h"
int main() {
char source[] = "This is the source. "; // placeholder text
int arr = convert(source);
for (int i = 0; i < 21; i++) {
for (int k = 0; k < 3; k++) {
printf("%d\n", arr[i][k]); // error occurs at this line.
}
}
return 0;
}
converter.c file:
// Converts an input string to its respective ASCII matrix.
#include <string.h>
#include <stdio.h>
#include "converter.h"
// Converts the entire string into an multi-dimensional array.
int convert(char text[]){
// copy the input text into a local store.
char store[strlen(text)];
strcpy(store, text);
// make sure the length of the input string is a multiple of 3 or make it so.
int excess = strlen(store)%3;
char excess_spaces[3] = " ";
if (excess != 0) {
strncat(store, excess_spaces, 3-excess);
}
// covert the source into an array
int arr[3][strlen(store)/3];
int steps = strlen(store)/3;
for (int i = 0; i < steps; i++) {
int t[3];
for (int k = 0; k < 3; k++) {
t[k] = (int) store[3*i+k];
arr[k][i] = t[k];
}
}
return arr;
}
converter.h file:
int convert(char text[]);
There are multiple issues in this code.
The allocating storage for string, one must include one byte for a null terminator. Replace:
char store[strlen(text)];
with:
char store[strlen(text) + 1];
Additionally store must be big enough to contain the excess which is up to 3 spaces.
char store[strlen(text) + 3 + 1];
In C you cannot use an array as a value. It is converted to a pointer to it's first element in pretty must every context. Therefore it is not possible to return an array directly. It could be workaround by wrapping an array with a struct but it a topic for another day.
As result return arr will be equivalent to return &arr[0] which is int (*)[XXX] a pointer to int array of size XXX.
Never ever return a pointer to an object with automatic storage. It's Undefined Behaviour. I know that the intention was returning an array not a pointer to it. Create an object with dynamic storage with malloc-like function to safely return a pointer.
Returning Variable Length Array (VLA) by value is not possible because Variably Modified (VM) types cannot be defined at file scope.
It looks that indices are swapped in:
printf("%d\n", arr[i][k]);
I guess it should be arr[k][i].
Now... let's solve it.
Returning VLA is tricky. One solution is to pass a pointer to VLA as an argument. See https://stackoverflow.com/a/14088851/4989451.
The issue with this solution is that the caller must be able to compute the dimensions.
The other way it to wrap the result of the convert() to a struct. Note that the function and the struct can share the name. The result with have the sizes of VLA as n and m members and the pointer to the data as arr. The caller need to cast it to proper VM type.
To cumbersome casts between the non-trivial pointer types, one can cast via void*.
When all work with the array is done, release it memory with free().
// Converts an input string to its respective ASCII matrix.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// Converts the entire string into an multi-dimensional array.
struct convert {
int n, m;
int *arr;
} convert(char text[]){
// copy the input text into a local store.
size_t textlen = strlen(text);
char store[textlen + 3 + 1];
strcpy(store, text);
// make sure the length of the input string is a multiple of 3 or make it so.
int excess = textlen % 3;
char excess_spaces[3] = " ";
if (excess != 0) {
strncat(store, excess_spaces, 3-excess);
}
size_t storelen = strlen(store);
// allocate VLA with dynamic storage
int (*arr)[storelen / 3] = malloc(3 * sizeof *arr);
// covert the source into an array
int steps = storelen / 3;
for (int i = 0; i < steps; i++) {
int t[3];
for (int k = 0; k < 3; k++) {
t[k] = (int) store[3*i+k];
arr[k][i] = t[k];
}
}
return (struct convert){ .n = 3, .m = steps, .arr = (int*)arr };
}
int main() {
char source[] = "This is the source. "; // placeholder text
struct convert res = convert(source);
int n = res.n, m = res.m;
int (*arr)[m] = (void*)res.arr;
for (int i = 0; i < n; i++, puts("")) {
for (int k = 0; k < m; k++) {
printf("%d ", arr[i][k]); // error occurs at this line.
}
}
free(arr);
return 0;
}

Reversing a string in C without the output being null

I am trying to reverse a string (character array) using the following code, but when I attempt to print the string, the value of null. This is a homework assignment, but I am trying to learn so any help would be appreciated.
void input_reverse_string(const char* inputStr, char* reverseStr)
{
int i = 0;
int length = 0;
for (; *(inputStr++) != '\0'; i++)
{
length++;
}
while (*inputStr)
{
*reverseStr = *inputStr;
inputStr++;
reverseStr++;
}
const char* chr_ptr = &inputStr[length - 1];
printf("I see a %s\n", *chr_ptr);
*reverseStr = '\0';
printf("%d", length);
/* return reverseStr; */
}
Several things are out of order:
That's a strange way of computing the length of a string. You are using an index variable that you don't need, and incrementing 3 things at the same time, it's unneeded to say the least.
After calculating the length, and incrementing the inputStr pointer up to its end, you don't reset the pointer, so it still points to the end of the string (actually, one after the end!).
Inside the while you are advancing both pointers (inputStr and reverseStr) in the same direction, which can't possibly be right if you want to reverse the string.
The correct way to do this would be:
Compute the length of the string. Either use strlen() or do it by hand, but you really only need to increment one variable to do this. You can avoid incrementing inputStr, just use a temporary pointer.
Start from inputStr + length and walk backwards. Either use a pointer and do -- or just index the string).
Here's a working example:
void reverse_string(const char* inputStr, char* reverseStr) {
unsigned len = 0;
int i;
while (inputStr[len])
len++;
for (i = len - 1; i >= 0; i--) {
reverseStr[len - i - 1] = inputStr[i];
}
reverseStr[len] = '\0';
}
int main(void) {
char a[6] = "hello";
char b[6];
reverse_string(a, b);
puts(b);
return 0;
}
Output:
olleh

exercise 9.7 Kochan. strange output

I am working to learn C using Kochan's Programming in C 4th edition. problem 9.7 the goal is to insert a string of characters into another array. I am supposed to write a function to accomplish this. I have two problems.
When I have the algorithm print the result as it goes through the if statements, it produces the desired output, however when I change it to an %s, I only get a partial output. My hunch is that a null character is being placed where i do not want it, but I simply cannot see it.
To see what was happening, I added a printf that would track the letter and the array space it was occupying. I was surprised to see that the first letter was not 0, but was blank, and the next letter was assigned the 0. Any insight into this would be appreciated.
The funtion of interest is "insertString".
#include <stdio.h>
#include <stdbool.h>
char x[] = {"the wrong son was shot that day"};
char text[] = {"per"};
int countString (char x[])
{
int counter, z;
for (counter = 0; x[counter] != '\0'; ++counter)
z = counter+1;
return z;
}
void insertString (char text[],char x[],int n) //source, text to input, where
{
int count, clock, i = countString(text), q = countString(x);
int counter = 0;
char y[i + q];
for(count = 0; x[count] != '\0'; ++count){
if (count < n){
y[count] = x[count];
printf("%c %i", y[count], count); //The integer call is just to put a number next to the
//letter. This is where my second issue is shown.
}
else if (counter <= i){
y[count] = text[counter];
++counter;
printf("%c", y[count]);
}
else{
y[count]= x[count - counter];
printf("%c", y[count]);
}
}
printf("\n\n");
y[count-counter] = '\0';
printf("%s", y);
}
int main (void)
{
void insertString(char text[], char x[], int i);
int countString(char x[]);
int i;
insertString(text, x, 10);
return 0;
}
10 out of 10 times I post here it is because im doing something dumb, so I use SO as an absolute last resort if i am getting into the territory of just randomly trying stuff with no methodology. Thanks for your patience in advance.
Your condition is wrong in the for. It should be x[count - counter] != '\0'
In the second condition use just < to avoid overindexing. (else if (counter < i))
You put the terminating NULL char at wrong place. You should do this: y[count] = '\0'
printf inside a string routine like this is fine for debugging, but it's a poor way to write a general-purpose function because it makes it impossible to use its output for further programmatic manipulation. It can also make it difficult to reason about how the state of the function interacts in unpredictable ways with the state of the printed data.
I assume you haven't learned about dynamic memory allocation which is a prerequisite to returning strings from functions. You can inline the function logic into main or printf only at the end of the function in the meantime.
Adding to this point, a void function would need to reallocate space in the string to insert into and would be in-place. This seems likely less generally useful than allocating a new string to hold the result.
Using global variables like char x[] when there's no need is poor practice. It's better to put those strings scoped to main. Since your function can access these variables in addition to its parameters, confusion can ensue when scope and encapsulation is breached.
Use consistent formatting and avoid variable names like q that mean virtually nothing. Instead of adding comments to explain poor var names:
void insertString (char text[],char x[],int n) //source, text to input, where
You can simply name the variables exactly what they represent:
void insertString(char *dest, char *source, int add_index)
Also, now that you've mastered countString, you can abstract this by calling the builtin strlen.
Be sure to allocate enough space in buffers: char y[i + q]; should be y[i+q+1] to allow room for the null terminator '\0'.
As for the logic, I think it's easier to break into three loops without conditions instead of one loop with conditions. This makes it easier to break the problem down into the three constituent steps:
Add everything up until add_index from the dest string to the result.
Add everything in the source string to the result.
Add everything after add_index from the dest string to the result.
Using this approach, all that's left is figuring out how to map the indexes appropriately. Here it is in code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *insert_string(char *dest, char *source, int add_index) {
int source_len = strlen(source);
int dest_len = strlen(dest);
int result_size = source_len + dest_len + 1;
char *result = malloc(result_size);
for (int i = 0; i < add_index; i++) {
result[i] = dest[i];
}
for (int i = 0; i < source_len; i++) {
result[i+add_index] = source[i];
}
for (int i = add_index; i < dest_len; i++) {
result[i+add_index] = dest[i];
}
result[result_size-1] = '\0';
return result;
}
int main(void) {
char *result = insert_string("hello world", "cruel ", 6);
printf("%s\n", result);
free(result);
return 0;
}
Although this is likely for instructional purposes, these operations can be abstracted further using builtin string functions like strncpy and sprintf.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *insert_string(char *dest, char *source, int add_index) {
int result_size = strlen(dest) + strlen(source) + 1;
char *result = malloc(result_size);
char pre[add_index+1];
pre[add_index] = '\0';
strncpy(pre, dest, add_index);
sprintf(result, "%s%s%s", pre, source, dest + add_index);
return result;
}
int main(void) {
char *result = insert_string("hello world", "cruel ", 6);
printf("%s\n", result);
free(result);
return 0;
}
Doing this in-place is more straightforward. Since the result already has the prefix, you can copy the destination postfix to create a source-sized gap in the middle and then overwrite the gap using the source string. It's up to the caller to make sure that the destination buffer is large enough to hold the insertion.
#include <stdio.h>
#include <string.h>
void insert_string(char *dest, char *source, int add_index) {
int source_len = strlen(source);
int dest_len = strlen(dest);
for (int i = add_index; i < dest_len; i++) {
dest[i+add_index] = dest[i];
}
for (int i = 0; i < source_len; i++) {
dest[i+add_index] = source[i];
}
}
int main(void) {
// allocate extra space in the string to hold the insertion
char greeting[32] = "hello world";
insert_string(greeting, "cruel ", 6);
printf("%s\n", greeting);
return 0;
}
A note of caution: none of these functions handle errors at all, so they're unsafe. Correct functions should check that the add_index falls within the bounds of the dest string. This is an exercise for the reader.
The original exercise is here:
Your function is not doing it. You need to insert the string into another string not to create a new one with both mixed. You can do it this way of course and then copy it into the original one - but it is the most uneficient way to archive it (memory & timewise).
Use the correct types.
size_t mystrlen(const char *str)
{
const char *end = str;
while(*end++);
return end - str - 1;
}
char *strinsert(char *dest, size_t pos, const char *istr)
{
char *temp = dest, *work;
size_t ilen = mystrlen(istr);
size_t nmove;
while(*temp) temp++;
nmove = temp - dest - pos + 1;
work = temp;
temp += ilen;
while(nmove--) *temp-- = *work--;
work = dest + pos;
while(*istr) *work++ = *istr++;
return dest;
}
int main()
{
char dest[128] = "0123456789012345678901234567890123456789";
printf("%s", strinsert(dest, 7, "ABCD"));
}
https://godbolt.org/z/KMnLU2

Reverse Function Array String

Why is my reverse function not reversing my string back to Hello! when i am calling my function the second time?
What could i change to use my function to reverse + dereverse my string multiple times?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void reverse(char arr[], int numberOfChars);
int main()
{
char myString[] = "Hello!";
int length = strlen(myString);
for (int i = 0; i < length; i++)
{
printf("%c", myString[i]);
}
printf("\n");
reverse(myString, length);
reverse(myString, length);
getchar();
return 0;
}
void reverse(char arr[], int numberOfChars)
{
for (int i = numberOfChars - 1; i >= 0; i--)
{
printf("%c", arr[i]);
}
getchar();
}
Because you never modify arr[] inside reverse(), you just print it in the order you iterate.
It should be something like:
void reverse(char *s, size_t length)
{
for(size_t i = 0; i < length / 2; ++i)
{
const size_t tail = length - (i + 1);
const char tmp = s[tail];
s[tail] = s[i];
s[i] = tmp;
}
}
Also no weird getchar() call in reverse(), that makes no sense.
If you want to reverse the words "Hello!", it is more convenient to define it as string and then use reverse(myString.begin(), myString.end()) orreverse(&myString[0], myString.length())
The parameter of the functionreverse(p1, p2) should be reverse(first_position, last_position)
Besides, if you really want to define the string as char, you should put them inside iteration and then reverse them one by one as #unwind said.
More details about the reverse function can be found at http://www.cplusplus.com/reference/algorithm/reverse/
You are using the same string the second time as well. Your function is void, you practically are doing nothing with the string itself, just printing the letters in reverse order. For what you want, you should save what you are doing in a variable and then return it, and maybe use a function to print separately.
The argument (myString) to the reverse function is same in two times when you called from the main function. You are just printing the char in reverse format instead of reverse in sub module.

Resources