c program dumping core on unix - c

I am a new learner of C language.
Below program run well on Windows but when i compile with gcc on solaris, this is dumping core
#include<stdio.h>
#include<stdlib.h>
void main()
{
char *name;
name="James Bond";
int i=0;
sprintf(name,"%s/%d",name,i);
printf("String is %s",name);
}
Please suggest

You cannot modify a string literal like that, it's undefined according to the standard. You're trying to overwrite that string literal with other data (the sprintf).
Many implementations will place them in read-only memory, causing a core dump - they're the good ones. The bad ones will continue on as if everything's okay, which it usually isn't.
You could try the following:
#include <stdio.h>
int main (void) {
char *name;
char name2[100]; // make sure plenty of space.
name = "James Bond";
int i = 0;
sprintf (name2, "%s/%d", name, i);
printf ("String is %s\n", name2);
return 0;
}
Most questions of this type have code like:
name = "Bob";
*name = 'J'; // to try and make "Job"
but it's just as undefined to write to string literals using sprintf as well.
Based on comments, you want to be able tocombine a path and file spec. You could do this as something like:
char *path = "/tmp/";
char *file = "xyz.txt"
char fullpath = malloc (strlen (path) + strlen (file) + 1);
if (fullpath == NULL)
// error and exit condition
strcpy (fullpath, path);
strcat (fullpath, file);
// use fullpath for your nefarious purposes :-)
free (fullpath);
That's one way to do it, there are others.

The correct way to define and initialize a constan string in C is
char name[]="James Bond";
Your code may be like this:
#include<stdio.h>
#include<stdlib.h>
void main()
{
char name[] = "James Bond";
int i = 0;
printf("String is %s/%d", name,i);
}

char *name;
name="James Bond"; // name is pointing into read-only memory
int i=0;
sprintf(name,"%s/%d",name,i); // trying to write to read-only memory
printf("String is %s",name);
instead use a buffer
char name[32] = "James Bond";
...

Your "name" string is insufficiently long to hold the set of characters you are printing to it with sprintf - you need to allocate a sufficient buffer for all of the characters.

You need to allocate memory for name pointer using malloc/calloc or defining it as a fixed length variable: char name[50] (for example)

On Linux and systems with the GNU Libc, you can also code using asprintf
char* str = NULL; // pointer should be initialized to NULL
asprintf (&str, "someformat %d", 20);
When using GTK, you could also call g_strdup_printf
You should understand the difference and similarities between arrays and pointers in C. Many many books or lectures explain that in detail.
Regards.

Related

how to touch a file to a particular location which was #defined [duplicate]

I'm working in C, and I have to concatenate a few things.
Right now I have this:
message = strcat("TEXT ", var);
message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
Now if you have experience in C I'm sure you realize that this gives you a segmentation fault when you try to run it. So how do I work around that?
In C, "strings" are just plain char arrays. Therefore, you can't directly concatenate them with other "strings".
You can use the strcat function, which appends the string pointed to by src to the end of the string pointed to by dest:
char *strcat(char *dest, const char *src);
Here is an example from cplusplus.com:
char str[80];
strcpy(str, "these ");
strcat(str, "strings ");
strcat(str, "are ");
strcat(str, "concatenated.");
For the first parameter, you need to provide the destination buffer itself. The destination buffer must be a char array buffer. E.g.: char buffer[1024];
Make sure that the first parameter has enough space to store what you're trying to copy into it. If available to you, it is safer to use functions like: strcpy_s and strcat_s where you explicitly have to specify the size of the destination buffer.
Note: A string literal cannot be used as a buffer, since it is a constant. Thus, you always have to allocate a char array for the buffer.
The return value of strcat can simply be ignored, it merely returns the same pointer as was passed in as the first argument. It is there for convenience, and allows you to chain the calls into one line of code:
strcat(strcat(str, foo), bar);
So your problem could be solved as follows:
char *foo = "foo";
char *bar = "bar";
char str[80];
strcpy(str, "TEXT ");
strcat(str, foo);
strcat(str, bar);
Avoid using strcat in C code. The cleanest and, most importantly, the safest way is to use snprintf:
char buf[256];
snprintf(buf, sizeof(buf), "%s%s%s%s", str1, str2, str3, str4);
Some commenters raised an issue that the number of arguments may not match the format string and the code will still compile, but most compilers already issue a warning if this is the case.
Strings can also be concatenated at compile time.
#define SCHEMA "test"
#define TABLE "data"
const char *table = SCHEMA "." TABLE ; // note no + or . or anything
const char *qry = // include comments in a string
" SELECT * " // get all fields
" FROM " SCHEMA "." TABLE /* the table */
" WHERE x = 1 " /* the filter */
;
Folks, use strncpy(), strncat(), or snprintf().
Exceeding your buffer space will trash whatever else follows in memory!
(And remember to allow space for the trailing null '\0' character!)
Also malloc and realloc are useful if you don't know ahead of time how many strings are being concatenated.
#include <stdio.h>
#include <string.h>
void example(const char *header, const char **words, size_t num_words)
{
size_t message_len = strlen(header) + 1; /* + 1 for terminating NULL */
char *message = (char*) malloc(message_len);
strncat(message, header, message_len);
for(int i = 0; i < num_words; ++i)
{
message_len += 1 + strlen(words[i]); /* 1 + for separator ';' */
message = (char*) realloc(message, message_len);
strncat(strncat(message, ";", message_len), words[i], message_len);
}
puts(message);
free(message);
}
Best way to do it without having a limited buffer size is by using asprintf()
char* concat(const char* str1, const char* str2)
{
char* result;
asprintf(&result, "%s%s", str1, str2);
return result;
}
If you have experience in C you will notice that strings are only char arrays where the last character is a null character.
Now that is quite inconvenient as you have to find the last character in order to append something. strcat will do that for you.
So strcat searches through the first argument for a null character. Then it will replace this with the second argument's content (until that ends in a null).
Now let's go through your code:
message = strcat("TEXT " + var);
Here you are adding something to the pointer to the text "TEXT" (the type of "TEXT" is const char*. A pointer.).
That will usually not work. Also modifying the "TEXT" array will not work as it is usually placed in a constant segment.
message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));
That might work better, except that you are again trying to modify static texts. strcat is not allocating new memory for the result.
I would propose to do something like this instead:
sprintf(message2, "TEXT %s TEXT %s", foo, bar);
Read the documentation of sprintf to check for it's options.
And now an important point:
Ensure that the buffer has enough space to hold the text AND the null character. There are a couple of functions that can help you, e.g., strncat and special versions of printf that allocate the buffer for you.
Not ensuring the buffer size will lead to memory corruption and remotely exploitable bugs.
Do not forget to initialize the output buffer. The first argument to strcat must be a null terminated string with enough extra space allocated for the resulting string:
char out[1024] = ""; // must be initialized
strcat( out, null_terminated_string );
// null_terminated_string has less than 1023 chars
As people pointed out string handling improved much. So you may want to learn how to use the C++ string library instead of C-style strings. However here is a solution in pure C
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void appendToHello(const char *s) {
const char *const hello = "hello ";
const size_t sLength = strlen(s);
const size_t helloLength = strlen(hello);
const size_t totalLength = sLength + helloLength;
char *const strBuf = malloc(totalLength + 1);
if (strBuf == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
strcpy(strBuf, hello);
strcpy(strBuf + helloLength, s);
puts(strBuf);
free(strBuf);
}
int main (void) {
appendToHello("blah blah");
return 0;
}
I am not sure whether it is correct/safe but right now I could not find a better way to do this in ANSI C.
It is undefined behaviour to attempt to modify string literals, which is what something like:
strcat ("Hello, ", name);
will attempt to do. It will try to tack on the name string to the end of the string literal "Hello, ", which is not well defined.
Try something this. It achieves what you appear to be trying to do:
char message[1000];
strcpy (message, "TEXT ");
strcat (message, var);
This creates a buffer area that is allowed to be modified and then copies both the string literal and other text to it. Just be careful with buffer overflows. If you control the input data (or check it before-hand), it's fine to use fixed length buffers like I have.
Otherwise, you should use mitigation strategies such as allocating enough memory from the heap to ensure you can handle it. In other words, something like:
const static char TEXT[] = "TEXT ";
// Make *sure* you have enough space.
char *message = malloc (sizeof(TEXT) + strlen(var) + 1);
if (message == NULL)
handleOutOfMemoryIntelligently();
strcpy (message, TEXT);
strcat (message, var);
// Need to free message at some point after you're done with it.
The first argument of strcat() needs to be able to hold enough space for the concatenated string. So allocate a buffer with enough space to receive the result.
char bigEnough[64] = "";
strcat(bigEnough, "TEXT");
strcat(bigEnough, foo);
/* and so on */
strcat() will concatenate the second argument with the first argument, and store the result in the first argument, the returned char* is simply this first argument, and only for your convenience.
You do not get a newly allocated string with the first and second argument concatenated, which I'd guess you expected based on your code.
You can write your own function that does the same thing as strcat() but that doesn't change anything:
#define MAX_STRING_LENGTH 1000
char *strcat_const(const char *str1,const char *str2){
static char buffer[MAX_STRING_LENGTH];
strncpy(buffer,str1,MAX_STRING_LENGTH);
if(strlen(str1) < MAX_STRING_LENGTH){
strncat(buffer,str2,MAX_STRING_LENGTH - strlen(buffer));
}
buffer[MAX_STRING_LENGTH - 1] = '\0';
return buffer;
}
int main(int argc,char *argv[]){
printf("%s",strcat_const("Hello ","world")); //Prints "Hello world"
return 0;
}
If both strings together are more than 1000 characters long, it will cut the string at 1000 characters. You can change the value of MAX_STRING_LENGTH to suit your needs.
You are trying to copy a string into an address that is statically allocated. You need to cat into a buffer.
Specifically:
...snip...
destination
Pointer to the destination array, which should contain a C string, and be large enough to contain the concatenated resulting string.
...snip...
http://www.cplusplus.com/reference/clibrary/cstring/strcat.html
There's an example here as well.
Assuming you have a char[fixed_size] rather than a char*, you can use a single, creative macro to do it all at once with a <<cout<<like ordering ("rather %s the disjointed %s\n", "than", "printf style format"). If you are working with embedded systems, this method will also allow you to leave out malloc and the large *printf family of functions like snprintf() (This keeps dietlibc from complaining about *printf too)
#include <unistd.h> //for the write example
//note: you should check if offset==sizeof(buf) after use
#define strcpyALL(buf, offset, ...) do{ \
char *bp=(char*)(buf+offset); /*so we can add to the end of a string*/ \
const char *s, \
*a[] = { __VA_ARGS__,NULL}, \
**ss=a; \
while((s=*ss++)) \
while((*s)&&(++offset<(int)sizeof(buf))) \
*bp++=*s++; \
if (offset!=sizeof(buf))*bp=0; \
}while(0)
char buf[256];
int len=0;
strcpyALL(buf,len,
"The config file is in:\n\t",getenv("HOME"),"/.config/",argv[0],"/config.rc\n"
);
if (len<sizeof(buf))
write(1,buf,len); //outputs our message to stdout
else
write(2,"error\n",6);
//but we can keep adding on because we kept track of the length
//this allows printf-like buffering to minimize number of syscalls to write
//set len back to 0 if you don't want this behavior
strcpyALL(buf,len,"Thanks for using ",argv[0],"!\n");
if (len<sizeof(buf))
write(1,buf,len); //outputs both messages
else
write(2,"error\n",6);
Note 1, you typically wouldn't use argv[0] like this - just an example
Note 2, you can use any function that outputs a char*, including nonstandard functions like itoa() for converting integers to string types.
Note 3, if you are already using printf anywhere in your program there is no reason not to use snprintf(), since the compiled code would be larger (but inlined and significantly faster)
int main()
{
char input[100];
gets(input);
char str[101];
strcpy(str, " ");
strcat(str, input);
char *p = str;
while(*p) {
if(*p == ' ' && isalpha(*(p+1)) != 0)
printf("%c",*(p+1));
p++;
}
return 0;
}
Try something similar to this:
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[])
{
// Insert code here...
char firstname[100], secondname[100];
printf("Enter First Name: ");
fgets(firstname, 100, stdin);
printf("Enter Second Name: ");
fgets(secondname,100,stdin);
firstname[strlen(firstname)-1]= '\0';
printf("fullname is %s %s", firstname, secondname);
return 0;
}
This was my solution
#include <stdlib.h>
#include <stdarg.h>
char *strconcat(int num_args, ...) {
int strsize = 0;
va_list ap;
va_start(ap, num_args);
for (int i = 0; i < num_args; i++)
strsize += strlen(va_arg(ap, char*));
char *res = malloc(strsize+1);
strsize = 0;
va_start(ap, num_args);
for (int i = 0; i < num_args; i++) {
char *s = va_arg(ap, char*);
strcpy(res+strsize, s);
strsize += strlen(s);
}
va_end(ap);
res[strsize] = '\0';
return res;
}
but you need to specify how many strings you're going to concatenate
char *str = strconcat(3, "testing ", "this ", "thing");

C sprintf overwrite?

Can someone explain me why this doesn't work? It appears that the program stops at sprintf(t->tuple[0], "abc"); and I don't know why. Really need help.
int testRemoveMeio(){
int result, i;
struct list_t *list = list_create();
char *tdata[3] = {" ", "2014", "Fixe!"};
struct tuple_t *t = tuple_create2(3, tdata);
struct tuple_t *tdups[4];
struct entry_t *entries[4];
sprintf(t->tuple[0], "abc");
tdups[0] = tuple_dup(t);
entries[0] = entry_create(tdups[0]);
list_add(list, entries[0]);
//extra code similar to above
return 0;
}
Edit:
struct tuple_t {
int tuple_dimension;
char **tuple;
};
struct tuple_t *tuple_create2(int tuple_dim, char **tuple){
struct tuple_t *t = (struct tuple_t *) malloc(sizeof(struct tuple_t));
if(t == NULL)
return NULL;
t->tuple_dimension = tuple_dim;
t->tuple = tuple;
return t;
}
Edited to add another example from the comments:
#include <stdio.h>
#include <string.h>
int main(void)
{
char * s = "ABC";
printf("%s\n",s);
sprintf(s,"DEF");
printf("%s\n",s);
return 0;
}
I pasted the code from your comment into the question. Both that and your original code are failing for the same reason, I think: you're modifying string literals.
It's sad but true that in C, string literals like "hello world" are illegal to modify, yet are assignable to char* without const and without a cast. This makes it easy to screw up, because modifying such a string is undefined behavior, because it may reside in read-only memory in your program.
To fix it, try this:
char tdata[3][6] = {" ", "2014", "Fixe!"};
Or in your second example:
char s[] = "ABC";
This way you are allocating an actual character array with writable storage. But please, always use snprintf() and never sprintf() because the latter is prone to buffer overruns which can crash your program or worse.
You second example is wrong. You should use snprintf(3) (there is no reason to use sprintf in 2014; it is old and dangerous, since it may give a buffer overflow) on some array of char like this:
#include <stdio.h>
int main(void) {
char buf[64];
snprintf(buf, sizeof(buf), "here %s", "ABC");
printf("%s\n",buf);
return 0;
}
You could have used some dynamically allocated memory zone (but then, you should know its size), e.g.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t siz=32;
char* ptr = malloc(siz);
if (!ptr) { perror("malloc"); exit(EXIT_FAILURE); };
snprintf(ptr, siz, "here %s and two is %d", "ABC", 2);
printf("%s\n", ptr);
free (ptr);
return 0;
}
You might use asprintf(3) if your system gives it (e.g. on Linux) like
#define _GNU_SOURCE
#include <stdio.h>
int main (void) {
char* ptrzone = NULL;
asprintf(&ptrzone, "and here %s and one is %d", "ABC", 1);
printf("%s\n", ptrzone);
free (ptrzone), ptrzone = NULL;
}
In serious programs, you often should use the result of snprintf.
Read the documentation of all the functions you are using, so also: perror(3), exit(3), malloc(3), free(3)
You absolutely should read more about C dynamic memory allocation
You should compile with all warnings and debug info (gcc -Wall -g) and learn to use the debugger (gdb) and the memory leak detector valgrind
Some important information is missing as the definition to struct tuple_t and the definition of function tuple_create2. If the error occurs on sprintf(t->tuple[0], "abc") then either t->tuple and/or t->tuple[0] is not correctly initialized/allocated. This former should be an array of at least 1 for the example (but more probably 3 if we look at tdata) strings and the latter to a string buffer (array of char). Check you or provide us the tuple_create2 function.
The way you use sprintf to copy a string is dangerous. On your example this works but if the string to copy contains the '%' character, bad things can happen (% is the character used to specify a format in printf/scanf family of functions. If you want to stay with sprinf use sprintf(t->tuple[0], "%s", "abc") but the simpler is strcpy(t->tuple[0], "abc")
Since you have now added the definition of tuple_create2, I try to answer.
In C, it is up to you to manage the memory. What do you expect from tuple_create2 ?. Your code allocates the space for the "header" (i.e. a struct tuple containing the dimension and an array of strings) and fills it with tuple. The result is a new object which points to the same memory for the data (i.e. the array of strings). This is OK except if you want to modify this array (which seems to be the case). There are 2 things: the array itself (each entry is a pointer to an array of chars - do you want to modify the pointers ?) and the strings (the content of the array of chars). There are several possibilities for this but this depends on you. For instance the function could allocate its own array of pointers and initialize with the existing data:
struct tuple_t *tuple_create2(int tuple_dim, char **tuple){
struct tuple_t *t = (struct tuple_t *) malloc(sizeof(struct tuple_t));
if(t == NULL)
return NULL;
t->tuple_dimension = tuple_dim;
t->tuple = (char **) malloc(sizeof(char *) * tuple_dim);
for(i = 0; i < tuple_dim; i++) // could be replaced by a memcpy
t->tuple[0] = tuple[0];
return t;
}
Then you have to be aware that we copied only pointers. So when you want to modify an element either you simply copy the pointer :
t->tuple[0] = "abc";
or you allocate a new string if you thing it can be modified and you don't want this. I give you an example with "abc" but this is not relevant because "abc" is a constant string which will not be modified. Anyway here is the code (note the use of stdrup which duplicates the string doing a malloc)
t->tuple[0] = strdup("abc");

Pointers confusion in C

i'm new to programming in C, and I've been thinking about this problem for quite some time now:
char* name;
scanf("%s", name);
Why doesn't this work? For example, if I type in "Hello", the program just gives me an error.
But isn't the above code the exact same thing as this?
char* name = "Hello";
char* name;
declares a pointer but doesn't initialise it to point to memory you have allocated. Attempts to write to it using scanf result in undefined behaviour and may well crash.
char* name = "Hello";
declares a pointer and initialises it to point to a string literal. String literals may be stored in read-only memory so you should think of this as having type const char*.
So, if you want to assign a string at run-time, neither of these approaches would work. You would instead have to allocate memory for a char array then use scanf (or fgets, readline, etc.) to write a string to that memory
char name[20];
scanf("%19s", name);
If you don't know the size of array before runtime , maybe you need a malloc
char* name = malloc(N); // you should initialize just N before use it.
scanf("%s", name);// It can work now , however it may case a overflow if you type too mach ,more than N-1
Or you can use
int n;
if(( n = read(STDIN_FILENO,name,N)) <0)
{printf("read error"); return -1;}
name[n] = 0;
Or
fgets(name,N,stdin) ;
Beside, after you used it, remeber free the memory
free(name);

Memory access violation. What's wrong with this seemingly simple program?

This is a quick program I just wrote up to see if I even remembered how to start a c++ program from scratch. It's just reversing a string (in place), and looks generally correct to me. Why doesn't this work?
#include <iostream>
using namespace std;
void strReverse(char *original)
{
char temp;
int i;
int j;
for (i = 0, j = strlen(original) - 1; i < j; i++, j--)
{
temp = original[i];
original[i] = original[j];
original[j] = temp;
}
}
void main()
{
char *someString = "Hi there, I'm bad at this.";
strReverse(someString);
}
If you change this, which makes someString a pointer to a read-only string literal:
char *someString = "Hi there, I'm bad at this.";
to this, which makes someString a modifiable array of char, initialized from a string literal:
char someString[] = "Hi there, I'm bad at this.";
You should have better results.
While the type of someString in the original code (char*) allows modification to the chars that it points to, because it was actually pointing at a string literal (which are not permitted to be modified) attempting to do any modification through the pointer resulted in what is technically known as undefined behaviour, which in your case was a memory access violation.
If this isn't homework, the C++ tag demands you do this by using the C++ standard library:
std::string s("This is easier.");
std::reverse(s.begin(), s.end());
Oh, and it's int main(), always int main(), dammit!
You're trying to modify a string literal - a string allocated in static storage. That's undefiend behaviour (usually crashes the program).
You should allocate memory and copy the string literal there prior to reversing, for example:
char *someString = "Hi there, I'm bad at this.";
char* stringCopy = new char[strlen( someString ) + 1];
strcpy( stringCopy, someString );
strReverse( stringCopy );
delete[] stringCopy;//deallocate the copy when no longer needed
The line
char *someString = "Hi there, I'm bad at this.";
makes someString point to a string literal, which cannot be modified. Instead of using a raw pointer, use a character array:
char someString[] = "Hi there, I'm bad at this.";
You can't change string literals (staticly allocated). To do what you want, you need to use something like:
int main()
{
char *str = new char[a_value];
sprintf(str, "%s", <your string here>);
strReverse(str);
delete [] str;
return 0;
}
[edit] strdup also works, also strncpy... i'm sure there's a variety of other methods :)
See sharptooth for explanation.
Try this instead:
#include <cstring>
void main()
{
char someString[27];
std::strcpy( someString, "Hi there, I'm bad at this." );
strReverse( someString );
}
Better yet, forget about char * and use <string> instead. This is C++, not C, after all.
When using more strict compiler settings, this code shouldn't even compile:
char* str = "Constant string";
because it should be constant:
const char* str = "Now correct";
const char str[] = "Also correct";
This allows you to catch these errors faster. Or you can just use a character array:
char str[] = "You can write to me, but don't try to write something longer!";
To be perfectly safe, just use std::string. You're using C++ after all, and raw string manipulation is extremely error-prone.

Copying a part of a string (substring) in C

I have a string:
char * someString;
If I want the first five letters of this string and want to set it to otherString, how would I do it?
#include <string.h>
...
char otherString[6]; // note 6, not 5, there's one there for the null terminator
...
strncpy(otherString, someString, 5);
otherString[5] = '\0'; // place the null terminator
Generalized:
char* subString (const char* input, int offset, int len, char* dest)
{
int input_len = strlen (input);
if (offset + len > input_len)
{
return NULL;
}
strncpy (dest, input + offset, len);
return dest;
}
char dest[80];
const char* source = "hello world";
if (subString (source, 0, 5, dest))
{
printf ("%s\n", dest);
}
char* someString = "abcdedgh";
char* otherString = 0;
otherString = (char*)malloc(5+1);
memcpy(otherString,someString,5);
otherString[5] = 0;
UPDATE:
Tip: A good way to understand definitions is called the right-left rule (some links at the end):
Start reading from identifier and say aloud => "someString is..."
Now go to right of someString (statement has ended with a semicolon, nothing to say).
Now go left of identifier (* is encountered) => so say "...a pointer to...".
Now go to left of "*" (the keyword char is found) => say "..char".
Done!
So char* someString; => "someString is a pointer to char".
Since a pointer simply points to a certain memory address, it can also be used as the "starting point" for an "array" of characters.
That works with anything .. give it a go:
char* s[2]; //=> s is an array of two pointers to char
char** someThing; //=> someThing is a pointer to a pointer to char.
//Note: We look in the brackets first, and then move outward
char (* s)[2]; //=> s is a pointer to an array of two char
Some links:
How to interpret complex C/C++ declarations and
How To Read C Declarations
You'll need to allocate memory for the new string otherString. In general for a substring of length n, something like this may work for you (don't forget to do bounds checking...)
char *subString(char *someString, int n)
{
char *new = malloc(sizeof(char)*n+1);
strncpy(new, someString, n);
new[n] = '\0';
return new;
}
This will return a substring of the first n characters of someString. Make sure you free the memory when you are done with it using free().
You can use snprintf to get a substring of a char array with precision:
#include <stdio.h>
int main()
{
const char source[] = "This is a string array";
char dest[17];
// get first 16 characters using precision
snprintf(dest, sizeof(dest), "%.16s", source);
// print substring
puts(dest);
} // end main
Output:
This is a string
Note:
For further information see printf man page.
You can treat C strings like pointers. So when you declare:
char str[10];
str can be used as a pointer. So if you want to copy just a portion of the string you can use:
char str1[24] = "This is a simple string.";
char str2[6];
strncpy(str1 + 10, str2,6);
This will copy 6 characters from the str1 array into str2 starting at the 11th element.
I had not seen this post until now, the present collection of answers form an orgy of bad advise and compiler errors, only a few recommending memcpy are correct. Basically the answer to the question is:
someString = allocated_memory; // statically or dynamically
memcpy(someString, otherString, 5);
someString[5] = '\0';
This assuming that we know that otherString is at least 5 characters long, then this is the correct answer, period. memcpy is faster and safer than strncpy and there is no confusion about whether memcpy null terminates the string or not - it doesn't, so we definitely have to append the null termination manually.
The main problem here is that strncpy is a very dangerous function that should not be used for any purpose. The function was never intended to be used for null terminated strings and it's presence in the C standard is a mistake. See Is strcpy dangerous and what should be used instead?, I will quote some relevant parts from that post for convenience:
Somewhere at the time when Microsoft flagged strcpy as obsolete and dangerous, some other misguided rumour started. This nasty rumour said that strncpy should be used as a safer version of strcpy. Since it takes the size as parameter and it's already part of the C standard lib, so it's portable. This seemed very convenient - spread the word, forget about non-standard strcpy_s, lets use strncpy! No, this is not a good idea...
Looking at the history of strncpy, it goes back to the very earliest days of Unix, where several string formats co-existed. Something called "fixed width strings" existed - they were not null terminated but came with a fixed size stored together with the string. One of the things Dennis Ritchie (the inventor of the C language) wished to avoid when creating C, was to store the size together with arrays [The Development of the C Language, Dennis M. Ritchie]. Likely in the same spirit as this, the "fixed width strings" were getting phased out over time, in favour for null terminated ones.
The function used to copy these old fixed width strings was named strncpy. This is the sole purpose that it was created for. It has no relation to strcpy. In particular it was never intended to be some more secure version - computer program security wasn't even invented when these functions were made.
Somehow strncpy still made it into the first C standard in 1989. A whole lot of highly questionable functions did - the reason was always backwards compatibility. We can also read the story about strncpy in the C99 rationale 7.21.2.4:
The strncpy function
strncpy was initially introduced into the C library to deal with fixed-length name fields in
structures such as directory entries. Such fields are not used in the same way as strings: the
trailing null is unnecessary for a maximum-length field, and setting trailing bytes for shorter
5 names to null assures efficient field-wise comparisons. strncpy is not by origin a “bounded
strcpy,” and the Committee preferred to recognize existing practice rather than alter the function
to better suit it to such use.
The Codidact link also contains some examples showing how strncpy will fail to terminate a copied string.
I think it's easy way... but I don't know how I can pass the result variable directly then I create a local char array as temp and return it.
char* substr(char *buff, uint8_t start,uint8_t len, char* substr)
{
strncpy(substr, buff+start, len);
substr[len] = 0;
return substr;
}
strncpy(otherString, someString, 5);
Don't forget to allocate memory for otherString.
#include <stdio.h>
#include <string.h>
int main ()
{
char someString[]="abcdedgh";
char otherString[]="00000";
memcpy (otherString, someString, 5);
printf ("someString: %s\notherString: %s\n", someString, otherString);
return 0;
}
You will not need stdio.h if you don't use the printf statement and putting constants in all but the smallest programs is bad form and should be avoided.
Doing it all in two fell swoops:
char *otherString = strncpy((char*)malloc(6), someString);
otherString[5] = 0;
char largeSrt[] = "123456789-123"; // original string
char * substr;
substr = strchr(largeSrt, '-'); // we save the new string "-123"
int substringLength = strlen(largeSrt) - strlen(substr); // 13-4=9 (bigger string size) - (new string size)
char *newStr = malloc(sizeof(char) * substringLength + 1);// keep memory free to new string
strncpy(newStr, largeSrt, substringLength); // copy only 9 characters
newStr[substringLength] = '\0'; // close the new string with final character
printf("newStr=%s\n", newStr);
free(newStr); // you free the memory
Try this code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* substr(const char *src, unsigned int start, unsigned int end);
int main(void)
{
char *text = "The test string is here";
char *subtext = substr(text,9,14);
printf("The original string is: %s\n",text);
printf("Substring is: %s",subtext);
return 0;
}
char* substr(const char *src, unsigned int start, unsigned int end)
{
unsigned int subtext_len = end-start+2;
char *subtext = malloc(sizeof(char)*subtext_len);
strncpy(subtext,&src[start],subtext_len-1);
subtext[subtext_len-1] = '\0';
return subtext;
}

Resources