void split(char array[]) {
int length, length2, half;
char first_half[BUF], sec_half[BUF];
length = strlen(array);
length2 = length / 2;
length -= length2;
strncpy(first_half, array, length - 1);
strncpy(sec_half, (array + length), length2 - 1);
printf("%s\n", first_half);
printf("%s\n", sec_half);
}
If input is "People", it outputs:
Pe0z
plcy etc... Just wondering what's the problem here.
My question is not the same as the question mentioned. I am not trying to insert a word in the middle of another word, I am trying to split a word in half and put the two halves in two strings.
OP's trouble is that first_half[BUF], sec_half[BUF] are not certainly null character terminated - a short coming of strncpy().
strncpy( first_half, array, length);
// printf( "%s\n", first_half );
// alternative limited width print, even if `first_half` lacks a null character.
printf( "%.*s\n", length, first_half );
trying to split a wordstring in half and put the two halves in two strings.
Below is a variable length array (VLA) approach.
I recommend memcpy() as that is often fastest for long strings and lest error prone than strncpy() #Blastfurnace. YMMV.
void split(const char array[]) {
size_t a_length = strlen(array);
size_t l_length = a_length / 2;
size_t r_length = a_length - l_length;
char l_half[l_length + 1], r_half[r_length + 1]; // + 1 for null character
memcpy(l_half, array, l_length);
l_half[l_length] = '\0';
memcpy(r_half, array + l_length, r_length + 1); // +1 for null character
printf("<%s>\n", l_half);
printf("<%s>\n", r_half);
}
size_t, an unsigned type, is the right sized integer type to use for array indexing. int maybe insufficient. Note that strlen() returns type size_t.
If all that is wanted is to print the 2 halves, not much code needed:
void split_print(const char array[]) {
int half = strlen(array) / 2;
printf("%.*s\n", half, array);
printf("%s\n", array + half);
}
One other issue not yet considered is "How do I handle words with an odd number of characters?". It's easy to split 1234 into 12 and 34, but how do you split 123? You must decide how to test for odd/even and decide which half gets the extra character (generally the first half, but it's up to you). You should also consider splitting strings of any size (and validate against processing a NULL pointer or empty-string passed to your function).
To handle checking odd/even length, all you need to do is check the 1st-bit of length on little-endian systems, or for complete portability just use modulo 2. If the 1st-bit (on little-endian) or the result of len % 2 is 0 it's even, otherwise the length is odd. (if odd, just add +1 character to the first half).
If your compiler supports Variable Length Array C99 extensions, the problem becomes simply a matter of declaring the two VLAs and letting the compiler handle the work, e.g.
void split_vla (char *s)
{
if (!s || !*s) { /* validate parameter not NULL or empty-string */
fprintf (stderr, "error: s NULL or empty-string.\n");
return;
}
size_t l = strlen (s),
n = (l % 2 == 0) ? l / 2 : l / 2 + 1;
char s1[n + 1], s2[n + 1]; /* declare VLAs */
memcpy (s1, s, n); /* memcpy chars to each half */
memcpy (s2, s + n, l - n);
s1[n] = 0; /* affirmatively nul-terminate */
s2[l - n] = 0;
printf ("s : %s\ns1 : %s\ns2 : %s\n", s, s1, s2);
}
If it doesn't, you can always dynamically allocate storage for each of the halfs (and if you choose calloc over malloc, then your storage is initialized to all zeros (providing a nul-byte at the end of each half), e.g.
void split_dyn (char *s)
{
if (!s || !*s) { /* validate parameter not NULL or empty-string */
fprintf (stderr, "error: s NULL or empty-string.\n");
return;
}
size_t l = strlen (s),
n = (l % 2 == 0) ? l / 2 : l / 2 + 1;
char *s1, *s2;
/* allocate storage for s1 & s2 and validate allocation */
if (!(s1 = calloc (n + 1, 1)) || !(s2 = calloc (n + 1, 1))) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
memcpy (s1, s, n); /* memcpy chars to each half */
memcpy (s2, s + n, l - n);
printf ("s : %s\ns1 : %s\ns2 : %s\n", s, s1, s2);
free (s1); /* don't forget to free the memory you allocate */
free (s2);
}
Either way is fine depending on what your compiler supports. You are free to use malloc and affirmatively nul-terminate as was done in the VLA example. Also be aware that alloca gives similar functionality to what you get with VLAs, but provides a bit more flexibility in the scope for your arrays (not relevant here since the VLAs are declared with function scope but be aware of the additional method). Give both examples a try and let me know if you have further questions.
Example Use/Output
$ ./bin/str_split_half 123456789
s : 123456789
s1 : 12345
s2 : 6789
$ ./bin/str_split_half 1234567890
s : 1234567890
s1 : 12345
s2 : 67890
$ ./bin/str_split_half 1
s : 1
s1 : 1
s2 :
Since I see that there is a concern about performance, I'd say get rid of strncpy altogether.
fist_half[l_length] = '\0';
while(l_length--)
first_half[l_length] = array[l_length];
The same method can be applied to the right side with some index modification.
This way you can get rid of overhead and HEADACES of strncpy.
If you use pointers the code can be even further simplified.
It is enough if you initialize the buffers with 0 as shown in split1(...)
char first_half[BUF] = {0}; // whole buffer is full of zeroes
char sec_half[BUF] = {0};
Then termination will be automatic.
The uninitialized buffer contains random characters.
If buffers are not zeroed the termination is needed as shown in split2(...)
The solutions are as close as possible to the original code. They work for even, odd and empty strings.
Please note the symmetry of the solutions with memcpy and strncpy.
#include <stdio.h>
#include <string.h>
#define BUF 255
void split1(char array[], int bUseMemcpy)
{
/* use zeroed buffers to automatically terminated the copied strings */
int length, length2;
char first_half[BUF] = {0};
char sec_half[BUF] = {0};
length = strlen( array );
length2 = length / 2;
length -= length2;
if(bUseMemcpy)
memcpy( first_half, array, length);
else
strncpy( first_half, array, length);
if(bUseMemcpy)
memcpy( sec_half, (array + length), length2);
else
strncpy( sec_half, (array + length), length2);
printf( "<%s>\n", first_half );
printf( "<%s>\n", sec_half );
}
void split2(char array[], int bUseMemcpy)
{
/* Do not initialize the buffers
Use 0 to terminate the buffers after the copy */
int length, length2;
char first_half[BUF];
char sec_half[BUF];
length = strlen(array);
length2 = length / 2;
length -= length2;
if(bUseMemcpy)
memcpy( first_half, array, length);
else
strncpy( first_half, array, length);
first_half[length]=0; /*zero termination needed, since buffers are not initialized to 0*/
if(bUseMemcpy)
memcpy( sec_half, (array + length), length2);
else
strncpy( sec_half, (array + length), length2);
sec_half[length2]=0; // zero termination
printf( "<%s>\n", first_half );
printf( "<%s>\n", sec_half );
}
int main(void) {
split1("123456789",0);
split1("",1);
split2("people",0);
split2("1",1);
return 0;
}
Output:
<12345>
<6789>
<>
<>
<peo>
<ple>
<1>
<>
There is a simple way to output the string split on 2 separate lines: use printf with the %.*s conversion format. It prints a initial portion of the string argument:
void split(const char *array) {
int half = strlen(array) / 2;
printf("%.*s\n%s\n", half, array, array + half);
}
Related
I have an array:
char arr[]="This is the string";
For instance, if I want to print only first 5 characters of that string, I have tried the following:
printf("%-5s",arr);
But it is printing whole string. Why?
You can use %.*s, it takes size of intended bytes to be printed and pointer to char as arguments when using with printf. For example,
// It prints This
printf("%.*s", 4, arr);
But it is printing whole string. Why?
You are using %-5s meaning the - left-justifies your text in that field.
En passant, the output cannot be achieved by using the accepted answer as simply as the code snippet, even if it may be seemed derisively.
int i;
char arr[]="This is the string";
for (i = 1; i < sizeof(arr); ++i) {
printf("%.*s\n", i, arr);
}
Output:
T
Th
Thi
This
This
This i
This is
This is
This is t
This is th
This is the
This is the
This is the s
This is the st
This is the str
This is the stri
This is the strin
This is the string
- is a printf formater for justification, not precision.
What you want is the . formater which is used for precision :
printf("%.5s", arr);
This will print the first 5 elements of arr.
If you want to learn more about printf formaters, take a look at this link.
for example substring extraction function (extracts substring to the buff)
char *strpart(char *str, char *buff, int start, int end)
{
int len = str != NULL ? strlen(str) : -1 ;
char *ptr = buff;
if (start > end || end > len - 1 || len == -1 || buff == NULL) return NULL;
for (int index = start; index <= end; index++)
{
*ptr++ = *(str + index);
}
*ptr = '\0';
return buff;
}
You can do it quite simply in a number of ways. With a loop, looping the number of times desired, picking off chars each time, you can walk a pointer down the string an temporary nul-terminate after the 5th character, or you can simply use strncpy to copy 5 chars to a buffer and print that. (that is probably the simplest), e.g.
#include <stdio.h>
#include <string.h>
int main (void)
{
char arr[]="This is the string",
buf[sizeof arr] = ""; /* note: nul-termination via initialization */
strncpy (buf, arr, 5);
printf ("'%s'\n", buf);
return 0;
}
Example Use/Output
$ ./bin/strncpy
'This '
Look things over and let me know if you have any questions.
If I need to find out length of a array with repeated '\0' character, what should I do? strlen won't be of use as it will simply stop with '\0'. In that case what is the best solution?
For example I have a buf;
now I don't know the length. I need to find out the length so that I can read whole data in it.
EDIT:
unsigned char buf[4096];
This buf has '\0' character in it. But it occurs in between data.I need to read the data even with '\0' character. strlen won't solve the purpose. So what is the way?
This is the part question from here : lzss decoding EOF character issue
Code is there. Please look at it.
There are 3 possibilities to determine array size in my mind:
The array is declared as array. The sizeof operator can be used. (Nice, it's comile-time resolved.)
The array is passed as pointer. The size cannot be determined from type. It has to be provided another way.
The array length can be determined by its contents. This is used for C strings but can be used for other types also. (Consider, that the end-marker consumes an element itself. Thus, the maximum length is one less than the capacity.)
Sample code test-array-size.c:
#include <stdio.h>
/* an array */
static int a[5] = { 0, 0, 0, 0, -1 };
/* a function */
void func(int a1[], int len1, int *a2)
{
/* size of a1 is passed as len1 */
printf("a1 has %d elements.\n", len1);
/* len of a2 is determined with end marker */
int len2;
for (len2 = 0; a2[len2] >= 0; ++len2);
printf("a2 has (at least) %d elements.\n", len2 + 1);
}
/* HOW IT DOES NOT WORK: */
void badFunc(int a3[5])
{
int len = sizeof a3 / sizeof a3[0]; /* number of elements */
printf("a3 seems to have %d elements.\n", len);
}
/* the main function */
int main()
{
/* length of a can be determined by sizeof */
int size = sizeof a; /* size in bytes */
int len = sizeof a / sizeof a[0]; /* number of elements */
printf("a has %d elements (consuming %d bytes).\n", len, size);
/* Because this is compile-time computable it can be even used for
* constants:
*/
enum { Len = sizeof a / sizeof a[0] };
func(a, Len, a);
badFunc(a);
/* done */
return 0;
}
Sample session:
$ gcc -std=c11 -o test-array-size test-array-size.c
test-array-size.c: In function 'badFunc':
test-array-size.c:19:20: warning: 'sizeof' on array function parameter 'a3' will return size of 'int *' [-Wsizeof-array-argument]
int len = sizeof a3 / sizeof a3[0]; /* number of elements */
^
test-array-size.c:17:18: note: declared here
void badFunc(int a3[5])
^
$ ./test-array-size.exe
a has 5 elements (consuming 20 bytes).
a1 has 5 elements.
a2 has (at least) 5 elements.
a3 seems to have 1 elements.
$
Really need help!
This code should find a largest palindrome in a string. Which means if there are "abcdcba" and "cdc" in the same string, it should print "abcdcba" out since the length is longer. The function takes a string str and 2 points i and j and determines whether the string from i to j is a palindrome. If it is a palindrome, returns the length of the palindrome and if it is not, returns -1.
int palindromelength(char *str, int i, int j){
int *first = &i, *last = &j;
int len;
while (first < last){
if (toupper(*first) != toupper(*last))
return -1;
first++;
last--;
}
len = last - first;
return (len);
}
int main() {
int length, i, j;
char str;
scanf("%s", &str);
length = strlen(str);
printf("Length = %d\n", palindromelength(str, i, j));
//should print out largest palindrome.
return 0;
}
What you describe and what the function is supposed to do are inconsistent:
"The function takes a string str and 2 points i and j and determines whether the string from i to j is a palindrome. If it is a palindrome, returns the length of the palindrome and if it is not, returns -1"
Therefore the function should returen either j - i or -1
char str;
scanf("%s", &str);
This is not how you should declare then initialize a string. Use instead:
char str[512];
scanf ("%s", str);
Also note that you'll need to ask the user to input the length of that string, and you'll need to pass that length as argument in the "palindromelength" function
You access the (i+1)th entry of your string like this:
str[i]
but before, you need to check that i is strictly lower than the length of your string. And don't forget to initialize i and j in your main() function
Before starting to code, write an algorithm in pseudocode which can solve your problem and evaluate its complexity. In this case, the comlpexity of the most obvious algorithm would be O(n^2), where n is the length of the string. This most obvious solution would be to check every substring, but maybe there are better algorithms: en.wikipedia.org/wiki/Longest_palindromic_substring
You send your function a string and two indexes, then immediately take the address of two indexes and proceeded to increment/decrement the indexes without any relation or regard to your string. That will never get you anywhere.
While it is fine to try and do all comparisons with indexes as integers, it is probably a bit easier to approach finding palindromes operating on strings and characters instead. You use the indexes to set the start and end position within the string. The indexes by themselves are just numbers. Your first and last should not hold the address to the intergers, they should hold the address of the first and last characters of your search string.
Below is a quick example of using the indexes to locate the start and end characters for your search. Note: I use p (pointer) for first and ep (end pointer) for your last. Look over the logic and let me know if you have questions. The program takes 3 arguments, the string, start and end indexes within the string (0 based indexes):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAXP 128
int get_palindrome (char *s, size_t i, size_t j);
int main (int argc, char **argv) {
if (argc < 4 ) {
fprintf (stderr, "error: insufficient input, usage: %s str i j\n", argv[0]);
return 1;
}
size_t i = atoi (argv[2]);
size_t j = atoi (argv[3]);
char palindrome[MAXP] = {0};
int len = get_palindrome (argv[1], i, j);
if (len > 0)
{
strncpy (palindrome, argv[1] + i, len);
printf ("\n palindrome: %s (%d chars)\n\n",
palindrome, len);
}
else
printf ("\n no palindrome for for given indexes.\n\n");
return 0;
}
int get_palindrome (char *s, size_t i, size_t j)
{
if (!s || *s == 0) return -1;
int len = 0;
char *p = s + i; /* set start/end pointers */
char *ep = s + j + 1;
char *sp = NULL;
int c = *ep; /* save char from string */
*ep = 0; /* null-terminate at end */
char *s2 = strdup (p); /* copy string to s2 */
*ep = c; /* replace original char */
p = s2; /* set s2 start/end ponters */
ep = s2 + j - i;
while (ep > p) /* check for palindrome */
{
if (toupper(*ep) != toupper(*p))
{
*ep = 0;
sp = NULL;
}
else if (!sp)
sp = p;
p++, ep--;
}
len = sp ? (int) strlen (sp) : -1; /* get length */
if (s2) free (s2); /* free copy of string */
return len; /* return len or -1 */
}
Output
$ ./bin/palindrome 1234abcdcba 4 10
palindrome: abcdcba (7 chars)
Note the use of size_t type instead of int for i & j. i & j are indexes and will not be negative for the purpose of this problem. Try to always choose your data type to best fit your data. It will help identify and prevent problems in your code.
Also note, you should make a copy of the string in the function (if you are concerned about preserving the original). Inserting null-terminating characters locating palindromes will alter the original string otherwise.
There is an easy to understand solution to find out longest palindrome in a string.
Key Concept: at the center of a palindrome, characters are always of the form
"....x y x...." or "......x x......"
step1: scan the string from start to end for the xyx or xx patterns and store the center indices in an auxiliary array.
step2: now around each center try to expand the string in both direction and store the lengths.
step3: return the max length.
This approach takes O(N2) order time.
Hy everybody!
I am trying to write a program that checks if a given string of text is a palindrome (for this I made a function called is_palindrome that works) and if any of it's substrings is a palindrome, and I can't figure out what is the optimal way to do this:
For example, for the string s = "abcdefg" it should first check "a", then "ab", "abc", "abcd" and so on, for each character
In Python this is the equivalent of
s[:1], s[:2], ... (a, ab, ...)
s[1:2], s[1:3] ... (b, bc, ...)
What function/method is there that I can use in a similar way in C ?
This is the one liner I use to get a slice of a string in C.
void slice(const char *str, char *result, size_t start, size_t end)
{
strncpy(result, str + start, end - start);
}
Pretty straightforward.
Given you've checked boundaries and made sure end > start.
This slice_str() function will do the trick, with end actually being the end character, rather than one-past-the-end as in Python slicing:
#include <stdio.h>
#include <string.h>
void slice_str(const char * str, char * buffer, size_t start, size_t end)
{
size_t j = 0;
for ( size_t i = start; i <= end; ++i ) {
buffer[j++] = str[i];
}
buffer[j] = 0;
}
int main(void) {
const char * str = "Polly";
const size_t len = strlen(str);
char buffer[len + 1];
for ( size_t start = 0; start < len; ++start ) {
for ( int end = len - 1; end >= (int) start; --end ) {
slice_str(str, buffer, start, end);
printf("%s\n", buffer);
}
}
return 0;
}
which, when used from the above main() function, outputs:
paul#horus:~/src/sandbox$ ./allsubstr
Polly
Poll
Pol
Po
P
olly
oll
ol
o
lly
ll
l
ly
l
y
paul#horus:~/src/sandbox$
There isn't; you'll have to write your own.
In order to check a string, you would need to supply to the number of characters to check in order to check for a palindrome:
int palindrome(char* str, int len)
{
if (len < 2 )
{
return 0;
}
// position p and q on the first and last character
char* p = str;
char* q = str + len - 1;
// compare start char with end char
for ( ; p < str + len / 2; ++p, --q )
{
if (*p != *q)
{
return 0;
}
}
return 1;
}
now you would need to call the function above for each substring (as you described it, i.e. always starting from the beginning) e.g.
char candidate[] = "wasitaratisaw";
for (int len = 0; len < strlen(candidate); ++len)
{
if (palindrome(candidate, len))
{
...
}
}
disclaimer: not compiled.
Honestly, you don't need a string slicing function just to check for palindromes within substrings:
/* start: Pointer to first character in the string to check.
* end: Pointer to one byte beyond the last character to check.
*
* Return:
* -1 if start >= end; this is considered an error
* 0 if the substring is not a palindrome
* 1 if the substring is a palindrome
*/
int
ispalin (const char *start, const char *end)
{
if (start >= end)
return -1;
for (; start < end; ++start)
if (*start != *--end)
return 0;
return 1;
}
With that, you can create the following:
int
main ()
{
const char *s = "madam";
/* i: index of first character in substring
* n: number of characters in substring
*/
size_t i, n;
size_t len = strlen (s);
for (i = 0; i < len; ++i)
{
for (n = 1; n <= len - i; ++n)
{
/* Start of substring. */
const char *start = s + i;
/* ispalin(s[i:i+n]) in Python */
switch (ispalin (start, start + n))
{
case -1:
fprintf (stderr, "error: %p >= %p\n", (void *) start, (void *) (start + n));
break;
case 0:
printf ("Not a palindrome: %.*s\n", (int) n, start);
break;
case 1:
printf ("Palindrome: %.*s\n", (int) n, start);
break;
} /* switch (ispalin) */
} /* for (n) */
} /* for (i) */
}
Of course, if you really wanted a string slicing function merely for output (since you technically shouldn't cast a size_t to int), and you still want to be able to format the output easily, the answer by Paul Griffiths should suffice quite well, or you can use mine or even one of strncpy or the nonstandard strlcpy, though they all have their strengths and weaknesses:
/* dest must have
* 1 + min(strlen(src), n)
* bytes available and must not overlap with src.
*/
char *
strslice (char *dest, const char *src, size_t n)
{
char *destp = dest;
/* memcpy here would be ideal, but that would mean walking the string twice:
* once by calling strlen to determine the minimum number of bytes to copy
* and once for actually copying the substring.
*/
for (; n != 0 && *src != 0; --n)
*destp++ = *src++;
*destp = 0;
return dest;
}
strslice actually works like a combination of strncpy and the nonstandard strlcpy, though there are differences between these three functions:
strlcpy will cut the copied string short to add a null terminator at dest[n - 1], so copying exactly n bytes before adding a null terminator requires you to pass n + 1 as the buffer size.
strncpy may not terminate the string at all, leaving dest[n - 1] equal to src[n - 1], so you would need to add a null terminator yourself just in case. If n is greater than the src string length, dest will be padded with null terminators until n bytes have been written.
strslice will copy up to n bytes if necessary, like strncpy, and will require an extra byte for the null terminator, meaning a maximum of n+1 bytes are necessary. It doesn't waste time writing unnecessary null terminators as strncpy does. This can be thought of as a "lightweight strlcpy" with a small difference in what n means and can be used where the resulting string length won't matter.
You could also create a memslice function if you wanted, which would allow for embedded null bytes, but it already exists as memcpy.
There is not any built-in function/method in any standard C library which can handle this. However, you can come up with your own method to do the same.
Given a char[] in c, I want to specify the length of output from that array starting with some position in printf, how can I conveniently do that?
For example, I want to print the portion from position 3 (indexed from 0) to position 8:
printf("%s", char_array+3..char_array+8)
I could make a temporary char[] with the desired length, but that is not very convenient. Or I could write a substring function
char* substring(const char* str, size_t begin, size_t len) {
if (str == 0 || strlen(str) == 0 || strlen(str) < begin || strlen(str) < (begin + len))
return 0;
return strndup(str + begin, len);
}
But if I call
printf("%s", substring(s, 3, 5));
I am afraid there will be memory leak.
What do you think about the best way to do this?
#include <stdio.h>
int printmid(const char *data, size_t start, int len) {
return printf("%.*s", len, data + start);
}
int main(void) {
char data[] = "Hello, World!";
printmid(data, 3, 6);
puts("");
return 0;
}
output
lo, Wo
int end = 8;
int bgn = 3;
int len = end - bgn + 1;
printf("%*.*s", len, len, char_array + bgn);
Note that len should be an int (and not, for example, the difference between two pointers - that's a ptrdiff_t or size_t). You can also omit the first length if you want - both can be specified, and they have specific meanings if the source string is shorter than the designated length (meaning there's a null byte in the string before char_array + end). Clearly, if the string in char_array is shorter than 4 bytes, then what follows the terminating null is probably garbage, and GIGO applies. If you're not certain the string is at least 8 bytes long, you might prefer to have the output left justified, in which case, insert a minus - before the first *; as written, the shorter string would be right justified.