I tried to reverse a string using c but the following snippet is not working and the output is not printed as expected,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void reverse(const char * orig);
int main(void)
{
char * string = "REVERSE";
reverse(string);
return 0;
}
void reverse(const char * orig)
{
int i = 0, j=strlen(orig);
int k = j;
printf("The string is : %s \n",orig);
char * new = (char *)malloc((j*sizeof(char))+1);
while(j > 0)
{
new[i++] = orig[j--];
}
new[k+1] = '\0';
printf("\n The Reversed string is : %s",new);
}
In the first loop while (j > 0), j is strlen(orig), thus orig[j--] is the string terminating '\0'.
With new[i++] = orig[j--]; where i == 0, the first character of new indicated the end of string, and thus the resulting string is always empty.
You may want to change it into new[i++] = orig[--j];.
You also need to change new[k+1] = '\0'; into new[k] = '\0'; to terminate the output string new correctly.
Algorithmic errors
j should start at strlen(orig)-1, otherwise you are copying the string terminator in the first position of new, thus making it a zero-length string;
the loop condition should read j>=0 - you do want to copy the first character of the target string;
you must manually terminate new with a NUL character;
Language usage errors
you are mallocing but not freeing - thus your reverse function is leaking memory;
the conversion from string literal to non-const char * (in main) is deprecated;
Stylistic warnings
sizeof(char) is 1 by definition, so it's useless to include it in the calculation;
although a valid variable name in C, new is a reserved keyword in C++, so you may want to use a different name (often C code ends up mixed in C++ code and/or editors use the same highlighter definition thus confusing matters).
The problem:
is that at the first iteration orig[j=strlen(orig)]` is the string terminator. You are placing the terminator at the beginning of the new string.
Change to
new[i++] = orig[--j];
live
Related
This question already has answers here:
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 1 year ago.
I'm trying to 'deep copy' a string so that I can perform operations on one copy, while retaining the original copy. This is the base example that I've got and for some reason the strncpy call causes a segfault. Please help
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main() {
char* stringA = "someVeryinTeresTingString";
char* stringB = malloc(sizeof(char) * strlen(stringA));
printf("A: %s, B: %s\n", stringA, stringB);
for (int i = 0; i < strlen(stringA); i++) {
stringB[i] = tolower(stringA[i]);
}
printf("A: %s, B: %s\n", stringA, stringB);
strncpy(stringA, stringB, strlen(stringA) - 1);
printf("A: %s, B: %s\n", stringA, stringB);
}
Easiest fix is to make a local copy of that string literal:
char stringA[] = "someVeryinTeresTingString";
Everything else works just the same.
Note that in the original code you have a pointer to immutable memory, while in this version you have a local (stack) array that is initialized with a copy of that string.
Another thing to note is if you're copying and manipulating C strings, do things like this:
char* stringB = strdup(stringA);
for (int i = 0; i < strlen(stringB); ++i) {
stringB[i] = tolower(stringB[i]);
}
Or even more efficiently by avoiding all these expensive strlen() calls:
char* stringB = strdup(stringA);
for (char* p = stringB; *p; ++p) {
*p = tolower(*p);
}
This line:
char* stringB = malloc(sizeof(char) * strlen(stringA));
shuld be like this:
char* stringB = malloc(sizeof(char) * (strlen(stringA) + 1));
then you will able to copy the \0 in the end of stringA
also, you want to copy to literal string - that is segmentation fault
char *strncpy(char *dest, const char *src, size_t n)
I'll try to comment and correct in your own code the mistakes I've seen:
(I will not correct things that can be eliminated or better done in another way, but are correct or not harmful, so you'll see only what must be corrected because of programming errors, and not questions about style or programming uses)
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main() {
char* stringA = "someVeryinTeresTingString";
/* you need to consider the space for the final null character in the malloc() call */
char* stringB = malloc(sizeof(char) * (strlen(stringA) + 1));
/* you don't need to use sizeof(char) as it is always equal to one.
* Multiplying by one is not necessary, but you'll probably know.
* char is warranteed by C standard that its sizeof is one. */
/* you need to copy the string *before* printing, or you will print an
* uninitialized string. Or at least initialize stringB to zeros, so you can
* use it with printf like functions (I do initialize the first char position to
* zero to make it appear as a length zero "" string)
* You will incurr in undefined behaviour if you don't do this. */
stringB[0] = '\0';
printf("A: %s, B: %s\n", stringA, stringB);
/* you need to copy the strings, so you can do it better if you test when
* stringA[i] == '\0', so you don't calculate the length of a string that is
* not going to change at every loop iteration. I will not change your
* code, because this is not an error. But strlen() searches from the
* beginning of the string for the '\0' char, character by character,
* and this test is done at every loop iteration. With the expression
* stringA[i] == 0 you do only a test per loop iteration to see if
* the char at position i in stringA is the null character. */
int i;
for (i = 0; i < strlen(stringA); i++) {
stringB[i] = tolower(stringA[i]);
}
/* you have not copied the final '\0', so I do it now. I need to move the
* declaration of i outside of the loop to be able to use it's value. */
stringB[i] = 0; /* you can use 0 or '\0' interchangeably */
printf("A: %s, B: %s\n", stringA, stringB);
/* nope. you need to copy the strings with a normal strcpy() as you know that
* both are the same length (better, you know that the space in stringB
* is the same as the length of stringA plus one). If you do this, you will not copy the last '\0' char, so wee need to append it.
* well, I don't know if that is what you want, so I don't actually touch anything here. */
strncpy(stringA, stringB, strlen(stringA) - 1);
/* stringB should be one char shorter than stringA */
printf("A: %s, B: %s\n", stringA, stringB);
}
by the way, you have been recommended to use strdup(3). This is a good idea, you don't need to be thinking on final nulls in this case, because strdup() takes care of it. Just remember that strdup(3) is not included in many C standard revisions, so you can get in trouble if you
move your program to a place lacking it (that should be very strange, anyway)
#include <stdio.h>
void append(char* s, char n);
void splitstr(char* string);
int main()
{
splitstr("COMPUTE 1-1");
printf("\n");
splitstr("COMPUTE 1+1");
printf("\n");
splitstr("COMPUTE 1*1");
return 0;
}
void append(char* s, char ch) {
while(*s != '\0'){
s = s + 1;
}
*s = ch;
s = s + 1;
*s = '\0';
}
void splitstr(char* string){
int count = 1;
char* expression = "";
while(*string != '\0'){
if(count > 8){
append(expression, *string);
string = string + 1;
count = count + 1;
}else{
string = string + 1;
count = count + 1;
}
}
printf("%s",expression);
}
Example Input and Output:
Input: COMPUTE 1+1
Output: 1+1
Input: COMPUTE 2-6
Output: 2-6
Originally, this code does not include stdio.h (I am doing this for testing on an online C compiler) because I am building an OS from scratch so I need to write all the functions by myself. I think the problem might be in the append function but I cannot find it.
instead of
char* expression = "";
do
char[MAX_expression_length+1] expression;
or use realloc in the append function
I think this line is the culprit:
append(expression, *string);
Notice how expression is declared:
char* expression = "";
In other words, expression consists of one byte, a single \0. Right away, we can see that append() won't work like you want it to--the while loop will never run, because *s is already \0.
But beyond that, the segfault likely happens at the bottom of append(). After the while loop, you unconditionally increment s and then write to the location it now points to. The problem is that this is a location that has never been allocated (since s is a reference to splitstr()'s expression, which is a single byte long). Furthermore, because expression is declared as a string constant, depending on your platform it may be placed in an area of memory marked read-only. Consequently, this is an attempt to write into memory that may not actually belong to the process and may also not be writable, raising the fault.
expression points to a string literal, and trying to modify a string literal leads to undefined behavior.
You need to define expression as an array of char large enough to store your final result:
char expression[strlen(string)+1]; // VLA
Since your result isn’t going to be any longer than the source string, this should be sufficient (provided your implementation supports VLAs).
tbh I thought it wouldn't be hard to learn C seeing as I already know several other languages, but I'm having trouble with my code, and I can't seem to figure out how to fix these errors. I specialize in Python, so this is much different because of all the specifications for types, pointers, etc. Anyway, here's the code below, sorry, I would paste the error, but it won't allow me to copy paste. I was using some print functions and found the error to be coming from line 9, "*returnStr += *str";. Thanks in advance for any help.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
char *multiplyString(const char *str, int num){
char *returnStr = "";
for (int i = 0; i < num; i++){
*returnStr += *str;
}
return returnStr;
}
int main(void){
bool asking = true;
int height;
const char *symbol = "#";
while (asking == true){
height = get_int("How tall should the pyramid be? pick a number between 1 and 8: ");
if (8 >= height && height >= 1){
asking = false;
}
}
for (int i=1; i<=height; i++){
printf("%s %s\n", strcat(multiplyString(" ", height-i), multiplyString(symbol, i)), multiplyString(symbol, i));
}
}
Change multiplyString() to the following
char *multiplyString(const char *str, int num) {
// + 1 for null-terminator
char *returnStr = calloc(sizeof(*returnStr), strlen(str)*num + 1);
for (int i = 0; i < num; i++) {
strcat(returnStr, str);
}
return returnStr;
}
You were attempting to modify a string literal, which is forbidden in C. Secondly, += is not string concatenation in C; rather, it was trying to perform integer addition on the first character of returnStr.
To fix this, you dynamically allocate the proper amount of memory using calloc() (which also initializes the memory to 0, which is necessary for strcat()). Then, in each iteration, append the string using strcat() to the end of the new string.
Remember to free the strings returned by this function later in the program, as they are dynamically allocated.
Two problems:
First of all, returnStr is pointing to a string literal, which is really an array of read only characters. In this case an array of only a single character, being the string terminator '\0'
Secondly, *returnStr += *str; makes no sense. It's the same as returnStr[0] = returnStr[0] + str[0]. And since the destination (returnStr[0]) is a string literal, attempting to write to it leads to undefined behavior
If you want to create a new string containing num copies of str, then you need to create a new string containing at least num * strlen(str) + 1 characters, the +1 for the terminator. Then you need to use strcat to concatenate into that new string.
Also if you allocate memory dynamically (with e.g. malloc) then you need to make sure that the first element is initialized to the string terminator.
I need help with char array. I want to create a n-lenght array and initialize its values, but after malloc() function the array is longer then n*sizeof(char), and the content of array isnt only chars which I assign... In array is few random chars and I dont know how to solve that... I need that part of code for one project for exam in school, and I have to finish by Sunday... Please help :P
#include<stdlib.h>
#include<stdio.h>
int main(){
char *text;
int n = 10;
int i;
if((text = (char*) malloc((n)*sizeof(char))) == NULL){
fprintf(stderr, "allocation error");
}
for(i = 0; i < n; i++){
//text[i] = 'A';
strcat(text,"A");
}
int test = strlen(text);
printf("\n%d\n", test);
puts(text);
free(text);
return 0;
}
Well before using strcat make
text[0]=0;
strcat expects null terminated char array for the first argument also.
From standard 7.24.3.1
#include <string.h>
char *strcat(char * restrict s1,
const char * restrict s2);
The strcat function appends a copy of the string pointed to by s2
(including the terminating null character) to the end of the string
pointed to by s1. The initial character of s2 overwrites the null
character at the end of s1.
How do you think strcat will know where the first string ends if you don't
put a \0 in s1.
Also don't forget to allocate an extra byte for the \0 character. Otherwise you are writing past what you have allocated for. This is again undefined behavior.
And earlier you had undefined behavior.
Note:
You should check the return value of malloc to know whether the malloc invocation was successful or not.
Casting the return value of malloc is not needed. Conversion from void* to relevant pointer is done implicitly in this case.
strlen returns size_t not int. printf("%zu",strlen(text))
To start with, you're way of using malloc in
text = (char*) malloc((n)*sizeof(char)
is not ideal. You can change that to
text = malloc(n * sizeof *text); // Don't cast and using *text is straighforward and easy.
So the statement could be
if(NULL == (text = (char*) malloc((n)*sizeof(char))){
fprintf(stderr, "allocation error");
}
But the actual problem lies in
for(i = 0; i < n; i++){
//text[i] = 'A';
strcat(text,"A");
}
The strcat documentation says
dest − This is pointer to the destination array, which should contain
a C string, and should be large enough to contain the concatenated
resulting string.
Just to point out that the above method is flawed, you just need to consider that the C string "A" actually contains two characters in it, A and the terminating \0(the null character). In this case, when i is n-2, you have out of bounds access or buffer overrun1. If you wanted to fill the entire text array with A, you could have done
for(i = 0; i < n; i++){
// Note for n length, you can store n-1 chars plus terminating null
text[i]=(n-2)==i?'A':'\0'; // n-2 because, the count starts from zero
}
//Then print the null terminated string
printf("Filled string : %s\n",text); // You're all good :-)
Note: Use a tool like valgrind to find memory leaks & out of bound memory accesses.
I have to compare few characters of string say from 2nd char till 4th character( counting starts from zero)
The string is stored in elements of structure say zoopla->real
for example zoopla ->real has '447889036' where real is of type char real[20];
Also please note I cant use function strnstr.
The code works as expected but just for curiousity, I have added printf statement and it shows me value till 4th cahr and then some garabe characters.
I want to know why the printf statment is showing 2 extra garabe values?
char * copyTemp;
char *strptr;
copyTemp = (char *)malloc(sizeof(char)*6);
strncpy(copyTemp, zoopla->real, 5);
printf("the string copied is %s", copyTemp); // debug statemnt
strptr = strstr(copyTemp, "666");
if(strptr != NULL)
{
//some other function
}
else
//some other function
free(copyTemp);
All criticism and suggestions are welcome
It seems to me that copyTemp is not null terminated. That's why printf shows you garbage characters after the characters you put in there. It doesn't know where to stop so it continues iterate through memory.
Add
copyTemp[5] = '\0';
after strncpy.
See this example from the documentation of strncpy:
/* strncpy example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[]= "To be or not to be";
char str2[6];
strncpy (str2,str1,5);
str2[5]='\0';
puts (str2);
return 0;
}
see
http://www.cplusplus.com/reference/clibrary/cstring/strncpy/
No null-character is implicitly appended to the end of destination, so destination will only be null-terminated if the length of the C string in source is less than num.
you have to add null your self.
if you will be allocating memory of constant size then use array only.
#include <stdio.h>
#include <string.h>
int main ()
{
char * copyTemp;
char *strptr;
copyTemp = (char *)calloc(sizeof(char),6);
strncpy(copyTemp, "88666782921", 5);
printf("the string copied is %s", copyTemp); // debug statemnt
strptr = strstr(copyTemp, "666");
if(strptr != NULL)
{
//some other function
}
else
//some other function
free(copyTemp);
return 0;
}
According to my old K&R, strncpy will only implicitly add null bytes if the source string has fewer characters than the number to be copied.
In this case, zoopla->real has more than 5 characters, so the function is simply copying the first five characters. Since you haven't initialized the memory to zero, or explicitly added a null byte, the string is not terminated after the fifth character. So when you print the string, you get additional bytes with essentially random values, until one is hit that happens to be zero.