I am trying to implement
void strcpyy(char *s, char *t){
while(*s++ = *t++){
}
}
which is an example from K&R. The implementation should be fairly easy but for some reason, that is not the case for me at the moment. So I have the following
int main(){
char *mess = "hello world";
char *mess = (char *) malloc(strlen(mess) + 1);
char *aess;
strcpyy(aess, mess);
printf("%s", aess);
return 0;
}
Every time I run the program, I keep on getting a big list of errors each time I run with -Wall. I would think that to implement and use strcpyy, you would have to malloc space to copy the string and once you do so, you should be able to print out aess which theoratically should contain a copy of mess. Any help would be much appreciated!
It is always a good practice to pay attention to the error messages, especially to the first message (others often are the consequences of the first error). The error message surely indicated the line number corresponding to the line with malloc, and most probably told you what's the problem there.
Correct your program to read:
char *mess = "hello world";
char *aess = (char *) malloc(strlen(mess) + 1);
or the complete function is:
int main(){
char *mess = "hello world";
char *aess = (char *) malloc(strlen(mess) + 1);
strcpyy(aess, mess);
printf("%s", aess);
return 0;
}
The problem is that your line
char *mess = (char *) malloc(strlen(mess) + 1);
overwrites the first line
char *mess = "hello world";
and the line
char *aess;
leaves the variable unassigned.
The compile error is because the compiler cannot choose between
char *mess = "hello world";
and
char *mess = (char *) malloc(strlen(mess) + 1);
which introduce a new variable each but with the same name.
The program will look the following way
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void strcpyy( char *s, const char *t )
{
while ( *s++ = *t++ );
}
int main( void )
{
char *t = "hello world";
char *s = ( char * )malloc( strlen( t ) + 1 );
strcpyy( s, t );
printf( "%s\n", s );
free( s );
return 0;
}
change
char *mess = "hello world";
char *mess = (char *) malloc(strlen(mess) + 1);
char *aess;
to
char *mess = "hello world";
char *aess = malloc(strlen(mess) + 1);
mess is a string literal, which is hold in read-only memory. you were overwriting it and losing string that you wanted to copy. you need to assign some space for place where you want to copy characters, in your case aess variable. also, remember to free(aess); at the end of your program. if not, you'll get memory leaks.
why are you declaring and defining mess two times? never declare two variables with the same name if they have the same scope ,by doing this you confuse the compiler;
I'd recommed using strdup like this :
int main(){
char *mess = strdup("hello world");
char *aess;
strcpyy(aess, mess);
printf("%s", aess);
return 0;
}
or just a plain array like this
int main(){
char mess[] = "hello world";
char *aess;
strcpyy(aess, mess);
printf("%s", aess);
return 0;
}
Related
this program it suppose to print Hello World but guess what exited, segmentation fault why is that happening ?
#include <stdio.h>
#include <string.h>
char f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char*str1 = "hello ";
char*str2 = "world!";
str1=f(str1, str2);
printf("%s", str1);
return 0;
}
You are not allowed to modify string literals. Use arrays with enough elements instead for strings to be modified.
Also assigning the return value of f to str1 is a bad idea because no return statement is executed in the function f and using its return value invokes undefined behavior. The return type should be changed to void if you are not going to return anything.
#include <stdio.h>
#include <string.h>
void f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char str1[16] = "hello ";
char*str2 = "world!";
f(str1, str2);
printf("%s", str1);
return 0;
}
First of all, this:
char*str1 = "hello ";
is a pointer to constant data, which means that you can't change the string "hello "
This is a constant pointer to variable data:
char str1[] = "hello ";
Which means that str1 always points to the same address in memory, but you can modify the content of that chunk of memory.
However str1 will have a fixed size of 7 characters (don't forget to count \0), so you can't append another string to it.
You could define a size #define SIZE 20 large enough to store both strings and declare
char str1[SIZE] = "hello ";
Or you could declare str1 as a VLA (variable length array) after having declared the string to append:
char*str2 = "world!";
char str1[strlen("hello ")+strlen(str2)+1] = "hello ";
Where the +1 is for \0.
Is it important that you copy characters one by one?
Because if it's not you can just copy one string to another like this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str1[] = "hello ";
char str2[] = "world!";
char *result = malloc(strlen(str1) + strlen(str2) + 1);
strcpy(result, str1);
strcat(result, str2);
printf("%s", result);
return 0;
}
First you are not allowed to change a constant string, that is undefined behaviour.
Secondly your f function has no return statement and thus returns random data, making the str1 variable in main point to random memory. Using it then also has undefined behaviour.
To fix it you should allocate new memory and concatenate the string into that
char* f(const char *s1, const char *s2)
{
char *s = malloc(strlen(s1) + strlen(s2) +1);
if (s) {
strcpy(s, s1);
strcat(s, s2);
}
return s;
}
The extra one byte allocated is for the terminating zero.
Both arguments are const as there is no reason to modify them, which allows both arguments to be literal strings.
For starters you may not change string literals (in this case the string literal pointed to by the pointer str1).
char*str1 = "hello ";
char*str2 = "world!";
Any attempt to change a string literal results in undefined behavior.
You need to allocate a character array large enough to store the result string with the appended string literal pointed to by the pointer str2.
Secondly there is already the standard C function strcat that performs the required task. If you have to write such a function yourself then it seems you should not use any string function as for example strlen.
And the return type char of your function does not make a sense. And moreover actually your function returns nothing.
So this assignment
str1=f(str1, str2);
results in undefined behavior.
The function and the program in whole can be written the following way without using standard string functions.
#include <stdio.h>
char * f( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
char s1[14] = "Hello ";
char *s2 = "World!";
puts( f( s1, s2 ) );
return 0;
}
The program output is
Hello World!
Pay attention to that the second function parameter shall have the qualifier const because the pointed string is not changed within the function. And the function return type should be char * that is the function should return the result string.
Is there a way to concatenate strings without pre-allocating a buffer?
Consider the following:
int main()
{
char buf1[] = "world!";
char buf2[100] = "hello ";
char * p = "hello ";
// printf("%s", strcat(p, buf1)); // UB
printf("%s", strcat(buf2, buf1)); // correct way to use strcat
return 0;
}
If I have a pointer that I want as prefix for a string, must I first copy it to a buffer and then strcat() it? Is there any function that does that implicitly?
The only options I thought of were strcat(), and sprintf(), and both require a buffer.
I need this for a function that expects one string, and I hoped for something close to the Python str1 + str2 syntax
Well, it's not standard C so not very portable, but on GNU libc systems you can use asprintf().
int main(void)
{
const char buf1[] = "world!";
const char * const p = "hello ";
char *s;
if (asprintf(&s, "%s%s", p, buf1) > 0 && s != NULL)
{
puts(s);
free(s);
}
return 0;
}
When compiled and run on a compliant system, this prints
hello world!
I you really want to use C, then you need to use buffers. In C++ or Python you can use constructors and operators that will hide the work for you, but in C you have to do things for yourself. You might create a little helper function if you want to make your code easier, but watch out for memory leaks and threading:
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
const char * strconcat(const char *p1, const char *p2)
{
static __thread char buffer[2048];
snprintf(buffer, 2048, "%s%s", p1, p2);
return buffer;
}
int main(int argc, char** argv)
{
const char *p1 = "hello ";
const char *p2 = "world!";
printf("%s\n", strconcat(p1, p2));
}
This example will work as long as the resulting string does not exceed 2048 characters; otherwise the resulting string will be truncated.
This is of course only one example of helper functions you could create.
Note that the above example returns a const char * which you cannot edit. If you want to further edit the string, you need to create a helper function which allocates a buffer, but then you need to manage your memory!
The most effective way to do this in run-time would be to call malloc and allocate room for a new string, then copy everything there. This is most likely what Python does behind the lines - though it will have a string type.
The disadvantage of doing this outside an ADT/class, is that you have to do the clean-up manually.
Using malloc + copy is however far faster than any *printf, it is thread safe and the same function can be re-used again. Example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* strdog (const char* s1, const char* s2)
{
size_t size1 = strlen(s1);
size_t size2 = strlen(s2);
char* result = malloc(size1 + size2 + 1);
if(result == NULL)
{
exit(EXIT_FAILURE);
}
memcpy(result, s1, size1);
memcpy(result+size1, s2, size2);
result[size1 + size2] = '\0';
return result;
}
inline void cleandog (char* s)
{
free(s);
}
int main (void)
{
char s1[] = "hello ";
char s2[] = "world";
char* str = strdog(s1, s2);
puts(str);
cleandog(str);
}
Note however that C supports compile-time concatenation. So if you are only using string literals, you should do something like this:
#define HELLO "hello "
#define WORLD "world"
...
const char* str = HELLO WORLD;
puts(str);
This is of course the superior version of them all, but only works with compile-time string literals.
Folks,
I have basic and simple question on pointers. The below is code is giving a segmentation fault.
int main()
{
char *str = "hello, world\n";
char *strc = "good morning\n";
strcpy(strc, str);
printf("%s\n", strc);
return 0;
}
Can't we copy from pointer to other.
if i have char *strc = "good morning\n", can't i do like this
strc[5] = '.';. Why this also giving a seg fault.
You may not change string literals. It is what you are trying to do in statement
strcpy(strc, str);
that is you are trying to overwrite string literal "good morning\n" pointed to by pointer strc.
Of cource you may use pointers in function strcpy. The valid code can look like
#include <stdio.h>
#include <string.h>
int main()
{
char *str = "hello, world\n";
char strc[] = "good morning\n";
strcpy(strc, str);
printf("%s\n", strc);
return 0;
}
Or
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *str = "hello, world\n";
char *strc = malloc( 14 * sizeof( char ) );
strcpy( strc, "good morning\n" );
//...
strcpy(strc, str);
printf("%s\n", strc);
free( strc );
return 0;
}
My plain C is a bit rusty, and I currently try to figure out why the first works and the second doesn't.
char *returnSomething(void) {
char *s = (char *) malloc(5 + 1);
strcpy(s, "Hello");
return s;
}
void dontReturnSomething(char *dest) {
char *s = (char *) malloc (5 + 1);
strcpy(s, "Hello");
dest = malloc(strlen(s) + 1);
strcpy(dest, s);
free(s);
}
int main(int argc, char *argv[]) {
char *first = returnSomething();
char *second = NULL;
dontReturnSomething(second);
printf("first: %s | second: %s", first, second);
}
Isn't it basically doing the same thing?
To return a pointer through a parameter you need a pointer to a pointer. Declare dest as char **dest.
void dontReturnSomething(char **dest) {
char *str = "Hello";
*dest = malloc(strlen(str) + 1);
strcpy(*dest, str);
}
Call the function like this:
dontReturnSomething(&second); // pass in address of second
To be more accurate, pointers to pointers are only necessary so long as, just as in the examples above, the memory is not allocated until after you enter the function. Just wanted to say this for anyone having pointer problems and thinks any passing of pointers always requires pointers to pointers to be passed.
For example, the below example works just fine.
void dontReturnSomething(int* testint)
{
int test = 33;
*testint = test;
}
int main(int argc, char *argv[])
{
int *first = calloc(1,sizeof(int));
printf("Before: %d\n", *first);
dontReturnSomething(first);
printf("After: %d\n", *first);
return(1);
}
If you run it, you'll get 0 and 33 as expected. Of course the caveat to this is that you absolutely have to have memory allocated to the pointer being used. If you allocated memory for the pointer inside the function, then you will be assigning it a new address that would then have to be returned so that the address can persist. The below example also works just fine.
void dontReturnSomething(char* testchar)
{
char* test = "Hello World!";
strcpy(testchar,test);
}
int main(int argc, char *argv[])
{
char *hello = NULL;
hello = calloc(13, sizeof(char));
printf("Before: %s\n", hello);
dontReturnSomething(hello);
printf("After: %s\n", hello);
return(1);
}
Of course you will pretty much never know the size of a string, or more usually a buffer, ahead of time. I just think it's important to understand the subtleties of pointers.
It's a textbook C code
void strcpy_new(char *s, char *t) {
while ((*s = *t) != '\0') {
s++;
t++;
}
}
int main(int argc, const char * argv[])
{
char *s = "this is line a";
char *t = "this is line b";
printf("%s", s);
strcpy_new(s, t);
printf("%s", s);
return 0;
}
when I run it with Xcode, I got EXEC_BAD_ACCESS.
The reason you get EXEC_BAD_ACCESS is because those string literals "this is line a" and "this is line b" are stored in read-only memory. Attempting to write to it (*s = *t) is undefined behavior and you are receiving a crash because of it.
To remedy this code you should allocate some memory for s so that it is large enough to hold the second string (t):
char s[] = "this is line a"; // contrived example, s and t are the same length
char *t = "this is line b";
strcpy_new(s, t);
I'm willing to bet that you're trying to run strcpy_new with a destination char *s that is a string literal
#include <string.h>
int main(int argc, char *argv[])
{
char *a = "Some String";
char *b = "Another string";
strcpy(b, a);
return 0;
}
will give an EXEC_BAD_ACCESS. The following, however, won't
#include <string.h>
int main(int argc, char *argv[])
{
char *a = "Some String";
char b[] = "Another string";
strcpy(b, a);
return 0;
}
The difference is that in the first case, b points to a block of memory in the __TEXT,__cstring,cstring_literals section of the executable, which is write protected. In the second case, it points to a block of memory on the stack.
The problem is that the effect of overwriting a string literal is undefined.
char *s = "this is line a";
char *t = "this is line b";
strcpy_new(s, t);
s and t are both off in the data section of the code, and your particular setup happens to give you an EXEC_BAD_ACCESS when you try changing them.
String literal are read-only. A good answer is found here: http://ubuntuforums.org/showthread.php?t=357869
String literals in C are read-only. In your sample code, "My string" is a string literal.
The str[] declaration copies the literal into writable memory (stack or heap). Therefore, your program can modify the string.
The * declaration initializes a pointer to the literal itself, so you have a pointer to a read-only segment. If you try to overwrite it, you get the SEGV.