Why is the following code printing !notreblo! instead of !notrebloH? Where is the ! coming from? I am trying to write a program that reverses an array and I am using the main function to test the rev_string function.
#include <stdio.h>
int main(void)
{
char s[11] = "Holberton!";
printf("%s\n", s);
rev_string(s);
printf("%s\n", s);
return (0);
}
void rev_string(char *s)
{
char new[500];
int count, newcount;
count = 0, newcount = 0;
while (*(s + count) != '\0')
{
*(new + count) = *(s + count);
count++;
}
count--;
while (count > 0)
{
*(s + newcount) = *(new + count);
count--;
newcount++;
}
}
The second while does not copy the first character, because the last character copied is at index 1. The condition tells it so: count > 0.
Change it to count >= 0.
(+1 for the famous "one-off" error. If I got 1 cent each time, I'll be a rich person.)
Notice your second while condition: while (count > 0). You aren't including your last character - e.g. if count == 3 (3 characters to reverse), you will only iterate twice - and your third character will not be written. You need to change the condition to while (count >= 0).
As a bonus, the function you are implementing is better known as strrev - and it can be implemented without an additional buffer.
Because you should change your second while condition to while (count >= 0)
Related
I'm trying to add an additional letter if there are two equal letters beside each other.
That's what I was thinking, but it doesn't put in an x between the two letters; instead of that, it copies one of the double letters, and now I have, for example, MMM instead of MXM.
for (index_X = 0; new_text[index_X] != '\0'; index_X++)
{
if (new_text[index_X] == new_text[index_X - 1])
{
double_falg = 1;
}
text[index_X] = new_text[index_X];
}
if (double_falg == 1)
{
for (counter_X = 0; text[counter_X] != '\0'; counter_X++)
{
transfer_X = counter_X;
if (text[transfer_X - 1] == text[transfer_X])
{
text_X[transfer_X] = 'X';
cnt_double++;
printf("%c\n", text[transfer_X]);
}
text_X[transfer_X] = text[transfer_X - cnt_double];
}
printf("%s\n", text_X);
}
If you're trying to create the modified array in text_X, copying data from new_text and putting an X between adjacent repeated letters (ignoring the possibility that the input contains XX), then you only need:
char new_text[] = "data with appalling repeats";
char text_X[SOME_SIZE];
int out_pos = 0;
for (int i = 0; new_text[i] != '\0'; i++)
{
text_X[out_pos++] = new_text[i];
if (new_text[i] == new_text[i+1])
text_X[out_pos++] = 'X';
}
text_X[out_pos] = '\0';
printf("Input: [%s]\n", new_text);
printf("Output: [%s]\n", text_X);
When wrapped in a basic main() function (and enum { SOME_SIZE = 64 };), that produces:
Input: [data with appalling repeats]
Output: [data with apXpalXling repeats]
To deal with repeated X's in the input, you could use:
text_X[out_pos++] = (new_text[i] == 'X') ? 'Q' : 'X';
It seems that your approach is more complicated than needed - too many loops and too many arrays involved. A single loop and two arrays should do.
The code below iterates the original string with idx to track position and uses the variable char_added to count how many extra chars that has been added to the new array.
#include <stdio.h>
#define MAX_LEN 20
int main(void) {
char org_arr[MAX_LEN] = "aabbcc";
char new_arr[MAX_LEN] = {0};
int char_added = 0;
int idx = 1;
new_arr[0] = org_arr[0];
if (new_arr[0])
{
while(org_arr[idx])
{
if (org_arr[idx] == org_arr[idx-1])
{
new_arr[idx + char_added] = '*';
++char_added;
}
new_arr[idx + char_added] = org_arr[idx];
++idx;
}
}
puts(new_arr);
return 0;
}
Output:
a*ab*bc*c
Note: The code isn't fully tested. Also it lacks out-of-bounds checking.
There is a lot left to be desired in your Minimal, Complete, and Verifiable Example (MCVE) (MCVE). However, that said, what you will need to do is fairly straight-forward. Take a simple example:
"ssi"
According to your statement, you need to add a character between the adjacent 's' characters. (you can use whatever you like for the separator, but if your input are normal ASCII character, then you can set the current char to the next ASCII character (or subtract one if current is the last ASCII char '~')) See ASCII Table and Description.
For example, you could use memmove() to shift all characters beginning with the current character up by one and then set the current character to the replacement. You also need to track the current length so you don't write beyond your array bounds.
A simple function could be:
#include <stdio.h>
#include <string.h>
#define MAXC 1024
char *betweenduplicates (char *s)
{
size_t len = strlen(s); /* get length to validate room */
if (!len) /* if empty string, nothing to do */
return s;
for (int i = 1; s[i] && len + 1 < MAXC; i++) /* loop until end, or out of room */
if (s[i-1] == s[i]) { /* adjacent chars equal? */
memmove (s + i + 1, s + i, len - i + 1); /* move current+ up by one */
if (s[i-1] != '~') /* not last ASCII char */
s[i] = s[i-1] + 1; /* set to next ASCII char */
else
s[i] = s[i-1] - 1; /* set to previous ASCII char */
len += 1; /* add one to len */
}
return s; /* convenience return so it can be used immediately if needed */
}
A short example program taking the string to check as the first argument could be:
int main (int argc, char **argv) {
char str[MAXC];
if (argc > 1) /* if argument given */
strcpy (str, argv[1]); /* copy to str */
else
strcpy (str, "mississippi"); /* otherwise use default */
puts (str); /* output original */
puts (betweenduplicates (str)); /* output result */
}
Example Use/Output
$ ./bin/betweenduplicated
mississippi
mistsistsipqpi
or when there is nothing to replace:
$ ./bin/betweenduplicated dog
dog
dog
Or checking the extremes:
$ ./bin/betweenduplicated "two spaces and alligators ~~"
two spaces and alligators ~~
two ! spaces ! and ! almligators ! ~}~
There are a number of ways to approach it. Let me know if you have further questions.
I want to write a recursive function which calculates Succ(‘2468’) = '2469'. ‘2468’ is a numeric string.
The exercice give me some predefined function such as last(ch), which returns the last caracter of a string, start(ch), returns ch without the last caracter, addEnd(ch, c), adds c at the end of ch and ask me to return a string as final result (i.e., suc("123")="124")
I tried this code but it works only for a string with 2 characters. If the length of my string is > 2, it doesn't work:
int successor (char*ch)
{
if (strlen (ch)==1)
return (int(*ch))+1);
else
return ((int(*ch))*10+successor(ch+1));}
There seems to be no need for multiplication or use of powers. Given the extra predefined functions you indicated were provided, I think the intention here was for a recursive way to express long addition with carry. I don't know C but here's an illustration in JavaScript that has very close syntax. I hope this helps.
function successor(s){
if (s.length == 1){
if (s == '9'){
return '10';
} else {
// Return the successor character,
// not sure how this looks in C.
return String.fromCharCode(
s.charCodeAt(0) + 1);
}
}
let rightmost = successor(last(s));
// No carry so just return
// the string with the last
// character incremented
if (rightmost != '10'){
return addEnd(start(s), rightmost);
// We have a carry so
// continue the recursion
} else {
return addEnd(successor(start(s)), '0');
}
}
function last(s){
return s.substr(-1);
}
function start(s){
return s.substr(0, s.length - 1);
}
function addEnd(s, c){
return s + c;
}
console.log(successor('2999'));
A key problem is this logic:
(int(*ch))*10+successor(ch+1)
the multiplication by 10 is insufficient for larger numbers. We need to multiply by a power of 10 and we already calculated that power but didn't hang onto it:
strlen (ch)
or more specifically:
strlen(ch) - 1
A complete solution:
#include <math.h>
#include <stdio.h>
#include <string.h>
#define digit(c) (c - '0')
int successor(char *string)
{
size_t power = strlen(string) - 1;
if (power == 0)
{
return digit(*string) + 1;
}
return digit(*string) * pow(10, power) + successor(string + 1);
}
int main() {
printf("%d\n", successor("2999"));
return 0;
}
OUTPUT
> ./a.out
3000
>
TODO
What happens if successor() is passed an empty string:
printf("%d\n", successor(""));
How can you modify the code to fix this? First decide what the function should return in this situation. What happens if successor() is passed a string that represents a number too large to be contained in an int:
printf("%d\n", successor("8589934592"));
How can you modify the code to fix this? Again, first decide what the function should return in this situation.
So i was doing some coding exercice on Talentbuddy (for those who know), and i cant get why i cant finish this one.
The exercice is removing a substring from a string, given as input the string, the position P where beginning to remove characters and N the number of characters needed to be remove.
Here is what i've done :
#include <stdio.h>
#include <unistd.h>
void remove_substring(char *s, int p, int n)
{
int idx;
idx = -1;
while (s[++idx] != '\0')
write(1, &s[idx == p - 1 ? idx + n : idx], 1);
}
When the input is "abcdefghi", P = 9 and N = 1, the result given is "abcdefgh" exactly the same as the one i get with my function. But TalentBuddy keep saying me that my output is wrong and i dont thing he (talentbuddy) is wrong.
Maybe there is a blank space or something between the "h" and the '\0'.
But i cant figure it cause when i add another write(1, "END", 3) at the end it appears like "abcdefghEND".
If the question is exclusively for strings( NULL Terminated )
Why can't this be as simple as this, unless it is a homework.
void removesubstr( const char *string, const char *substring )
{
char *p = strstr(string, substring);
if(p)
{
strcpy(p,p+strlen(substring));
}
}
Your problem is that you write something for every original index, even if it should be suppressed. What you write looks like abcdefgh, but it is abcdefgh<nul>, where the terminal doesn't render the <nul>.
You are mixing two methods here. Either filter out the removed substring:
void remove_substring(char *s, int p, int n)
{
int i = 0;
p--; /* convert to C-style index */
while (s[i] != '\0') {
if (i < p || i >= p + n) putchar(s[i]);
i++;
}
}
or skip the substring by jumping over it:
void remove_substring(char *s, int p, int n)
{
int i = 0;
int l = strlen(s);
while (i < l) {
if (i + 1 == p) {
i += n;
} else {
putchar(s[i++]);
}
}
}
You're trying to do a bit of both.
(I've avoided the awkward combination of prefix increment and starting at minus 1. And I've used putchar instead of unistd's write. And the termination by length is so you don't inadvertently jump beyond the terminating <nul>.)
At the end of Chapter 1 of The C Programming Language, there are a few exercises to complete. The one I am doing now asks you to make a program that wraps a long string of text into multiple lines at a specific length. The following function works 100%, aside from the last line which does not get wrapped, no matter the specified maximum width of a line.
// wrap: take a long input line and wrap it into multiple lines
void wrap(char s[], const int wrapline)
{
int i, k, wraploc, lastwrap;
lastwrap = 0; // saves character index after most recent line wrap
wraploc = 0; // used to find the location for next word wrap
for (i = 0; s[i] != '\0'; ++i, ++wraploc) {
if (wraploc >= wrapline) {
for (k = i; k > 0; --k) {
// make sure word wrap doesn't overflow past maximum length
if (k - lastwrap <= wrapline && s[k] == ' ') {
s[k] = '\n';
lastwrap = k+1;
break;
}
}
wraploc = 0;
}
} // end main loop
for (i = 0; i < wrapline; ++i) printf(" ");
printf("|\n");
printf("%s\n", s);
}
I have found the issue to be with the variable wraploc, which is incremented until it is greater than wrapline (the maximum index of a line). Once it is greater than wrapline, a newline is inserted at the appropriate location and wraploc is reset to 0.
The problem is that on the last line, wraploc is never greater than wrapline, even when it should be. It increments perfectly throughout iteration of the string, until the last line. Take this example:
char s[] = "This is a sample string the last line will surely overflow";
wrap(s, 15);
$ ./a.out
|
this is a
sample string
the last line
will surely overflow
The line represents the location where it should be wrapped. In this case, wraploc has the value 14, when there are clearly more characters than that.
I have no idea why this is happening, can someone help me out?
(Also I'm a complete beginner to C and I have no experience with pointers so please stay away from those in your answers, thanks).
You increment wraploc with i until it reaches wrapline (15 in the example).
When you wrap, you backtrack from i, back to the last whitespace.
That means that in your next line you already have some characters between the lastwrap location and i, i.e., you can't reset wraploc to 0 there.
Try setting wraploc = i-lastwrap instead.
Anybody who might, like me, find this question and run into a problem with new-lines in the source string.
This is my answer:
inline int wordlen(const char * str){
int tempindex=0;
while(str[tempindex]!=' ' && str[tempindex]!=0 && str[tempindex]!='\n'){
++tempindex;
}
return(tempindex);
}
void wrap(char * s, const int wrapline){
int index=0;
int curlinelen = 0;
while(s[index] != '\0'){
if(s[index] == '\n'){
curlinelen=0;
}
else if(s[index] == ' '){
if(curlinelen+wordlen(&s[index+1]) >= wrapline){
s[index] = '\n';
curlinelen = 0;
}
}
curlinelen++;
index++;
}
}
So pray tell, how would I go about getting the largest contiguous string of letters out of a string of garbage in C? Here's an example:
char *s = "(2034HEY!!11 th[]thisiswhatwewant44";
Would return...
thisiswhatwewant
I had this on a quiz the other day...and it drove me nuts (still is) trying to figure it out!
UPDATE:
My fault guys, I forgot to include the fact that the only function you are allowed to use is the strlen function. Thus making it harder...
Uae strtok() to split your string into tokens, using all non-letter characters as delimiters, and find the longest token.
To find the longest token you will need to organise some storage for tokens - I'd use linked list.
As simple as this.
EDIT
Ok, if strlen() is the only function allowed, you can first find the length of your source string, then loop through it and replace all non-letter characters with NULL - basically that's what strtok() does.
Then you need to go through your modified source string second time, advancing one token at a time, and find the longest one, using strlen().
This sounds similar to the standard UNIX 'strings' utility.
Keep track of the longest run of printable characters terminated by a NULL.
Walk through the bytes until you hit a printable character. Start counting. If you hit a non-printable character stop counting and throw away the starting point. If you hit a NULL, check to see if the length of the current run is greater then the previous record holder. If so record it, and start looking for the next string.
What defines the "good" substrings compared to the many others -- being lowercase alphas only? (i.e., no spaces, digits, punctuation, uppercase, &c)?
Whatever the predicate P that checks for a character being "good", a single pass over s applying P to each character lets you easily identify the start and end of each "run of good characters", and remember and pick the longest. In pseudocode:
longest_run_length = 0
longest_run_start = longest_run_end = null
status = bad
for i in (all indices over s):
if P(s[i]): # current char is good
if status == bad: # previous one was bad
current_run_start = current_run_end = i
status = good
else: # previous one was also good
current_run_end = i
else: # current char is bad
if status == good: # previous one was good -> end of run
current_run_length = current_run_end - current_run_start + 1
if current_run_length > longest_run_length:
longest_run_start = current_run_start
longest_run_end = current_run_end
longest_run_length = current_run_length
status = bad
# if a good run ends with end-of-string:
if status == good: # previous one was good -> end of run
current_run_length = current_run_end - current_run_start + 1
if current_run_length > longest_run_length:
longest_run_start = current_run_start
longest_run_end = current_run_end
longest_run_length = current_run_length
Why use strlen() at all?
Here's my version which uses no function whatsoever.
#ifdef UNIT_TEST
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif
/*
// largest_letter_sequence()
// Returns a pointer to the beginning of the largest letter
// sequence (including trailing characters which are not letters)
// or NULL if no letters are found in s
// Passing NULL in `s` causes undefined behaviour
// If the string has two or more sequences with the same number of letters
// the return value is a pointer to the first sequence.
// The parameter `len`, if not NULL, will have the size of the letter sequence
//
// This function assumes an ASCII-like character set
// ('z' > 'a'; 'z' - 'a' == 25; ('a' <= each of {abc...xyz} <= 'z'))
// and the same for uppercase letters
// Of course, ASCII works for the assumptions :)
*/
const char *largest_letter_sequence(const char *s, size_t *len) {
const char *p = NULL;
const char *pp = NULL;
size_t curlen = 0;
size_t maxlen = 0;
while (*s) {
if ((('a' <= *s) && (*s <= 'z')) || (('A' <= *s) && (*s <= 'Z'))) {
if (p == NULL) p = s;
curlen++;
if (curlen > maxlen) {
maxlen = curlen;
pp = p;
}
} else {
curlen = 0;
p = NULL;
}
s++;
}
if (len != NULL) *len = maxlen;
return pp;
}
#ifdef UNIT_TEST
void fxtest(const char *s) {
char *test;
const char *p;
size_t len;
p = largest_letter_sequence(s, &len);
if (len && (len < 999)) {
test = malloc(len + 1);
if (!test) {
fprintf(stderr, "No memory.\n");
return;
}
strncpy(test, p, len);
test[len] = 0;
printf("%s ==> %s\n", s, test);
free(test);
} else {
if (len == 0) {
printf("no letters found in \"%s\"\n", s);
} else {
fprintf(stderr, "ERROR: string too large\n");
}
}
}
int main(void) {
fxtest("(2034HEY!!11 th[]thisiswhatwewant44");
fxtest("123456789");
fxtest("");
fxtest("aaa%ggg");
return 0;
}
#endif
While I waited for you to post this as a question I coded something up.
This code iterates through a string passed to a "longest" function, and when it finds the first of a sequence of letters it sets a pointer to it and starts counting the length of it. If it is the longest sequence of letters yet seen, it sets another pointer (the 'maxStringStart' pointer) to the beginning of that sequence until it finds a longer one.
At the end, it allocates enough room for the new string and returns a pointer to it.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int isLetter(char c){
return ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') );
}
char *longest(char *s) {
char *newString = 0;
int maxLength = 0;
char *maxStringStart = 0;
int curLength = 0;
char *curStringStart = 0;
do {
//reset the current string length and skip this
//iteration if it's not a letter
if( ! isLetter(*s)) {
curLength = 0;
continue;
}
//increase the current sequence length. If the length before
//incrementing is zero, then it's the first letter of the sequence:
//set the pointer to the beginning of the sequence of letters
if(curLength++ == 0) curStringStart = s;
//if this is the longest sequence so far, set the
//maxStringStart pointer to the beginning of it
//and start increasing the max length.
if(curLength > maxLength) {
maxStringStart = curStringStart;
maxLength++;
}
} while(*s++);
//return null pointer if there were no letters in the string,
//or if we can't allocate any memory.
if(maxLength == 0) return NULL;
if( ! (newString = malloc(maxLength + 1)) ) return NULL;
//copy the longest string into our newly allocated block of
//memory (see my update for the strlen() only requirement)
//and null-terminate the string by putting 0 at the end of it.
memcpy(newString, maxStringStart, maxLength);
newString[maxLength + 1] = 0;
return newString;
}
int main(int argc, char *argv[]) {
int i;
for(i = 1; i < argc; i++) {
printf("longest all-letter string in argument %d:\n", i);
printf(" argument: \"%s\"\n", argv[i]);
printf(" longest: \"%s\"\n\n", longest(argv[i]));
}
return 0;
}
This is my solution in simple C, without any data structures.
I can run it in my terminal like this:
~/c/t $ ./longest "hello there, My name is Carson Myers." "abc123defg4567hijklmnop890"
longest all-letter string in argument 1:
argument: "hello there, My name is Carson Myers."
longest: "Carson"
longest all-letter string in argument 2:
argument: "abc123defg4567hijklmnop890"
longest: "hijklmnop"
~/c/t $
the criteria for what constitutes a letter could be changed in the isLetter() function easily. For example:
return (
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c == '.') ||
(c == ' ') ||
(c == ',') );
would count periods, commas and spaces as 'letters' also.
as per your update:
replace memcpy(newString, maxStringStart, maxLength); with:
int i;
for(i = 0; i < maxLength; i++)
newString[i] = maxStringStart[i];
however, this problem would be much more easily solved with the use of the C standard library:
char *longest(char *s) {
int longest = 0;
int curLength = 0;
char *curString = 0;
char *longestString = 0;
char *tokens = " ,.!?'\"()#$%\r\n;:+-*/\\";
curString = strtok(s, tokens);
do {
curLength = strlen(curString);
if( curLength > longest ) {
longest = curLength;
longestString = curString;
}
} while( curString = strtok(NULL, tokens) );
char *newString = 0;
if( longest == 0 ) return NULL;
if( ! (newString = malloc(longest + 1)) ) return NULL;
strcpy(newString, longestString);
return newString;
}
First, define "string" and define "garbage". What do you consider a valid, non-garbage string? Write down a concrete definition you can program - this is how programming specs get written. Is it a sequence of alphanumeric characters? Should it start with a letter and not a digit?
Once you get that figured out, it's very simple to program. Start with a naive method of looping over the "garbage" looking for what you need. Once you have that, look up useful C library functions (like strtok) to make the code leaner.
Another variant.
#include <stdio.h>
#include <string.h>
int main(void)
{
char s[] = "(2034HEY!!11 th[]thisiswhatwewant44";
int len = strlen(s);
int i = 0;
int biggest = 0;
char* p = s;
while (p[0])
{
if (!((p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z')))
{
p[0] = '\0';
}
p++;
}
for (; i < len; i++)
{
if (s[i] && strlen(&s[i]) > biggest)
{
biggest = strlen(&s[i]);
p = &s[i];
}
}
printf("%s\n", p);
return 0;
}