I have the below code which concatenates two strings. The first one with while condition works, but the second one with for loop fails. I ran them independently with the below inputs.
int original[100]="c" , add[50] = "pgm";
concatenate_string(original, add);
printf("String after concatenation is \"%s\"\n", original);
//strcat(original,add);
//printf("strcat is : %s",original);
void concatenate_string(char *original, char *add)
{
while(*original)
original++;
while(*add)
{
*original = *add;
add++;
original++;
}
*original = '\0';
}
void strcat(char *original,char *add)
{
for (;*original++;);
for (;*add;)
*original++=*add++;
*(original)='\0';
}
Because in second code, you are appending string after nul \0 symbol:
for (;*original++;);
^ always increments, even after nul found
should be:
for (;*original; original++);
Note:
for code:
for (;*original++;);
is equivalent to
while (*original++);
But not what you are using.
Your second version does an extra ++ before the second loop starts. Try adding --original; between the two loops, or as the initialization in the second loop.
#include<stdio.h>
#include<string.h>
void string_add(char *original,char *add) {
int i = 0,j,length = 0;
i = strlen(original);
length = strlen(add);
for(j = 0; j<length; j++,i++)
original[i] = add[j];
}
int main()
{
char original[20] = "I am from ", add[10] = "india";
string_add(original, add);
printf("Concatinated : %s\n",original);
return 0;
}
Related
The output result after execution is______
#include<stdio.h>
int main()
{ char str[]="xyz",*ps=str;
while(*ps)
ps++;
for(ps--;ps-str>=0;ps--)
puts(ps);
return 0;
}
The right answer is
z
yz
xyz
My logic is
After while(*ps) ps++; *psrepresents " " the last element of the array
When execute codefor(ps--;ps-str>=0;ps--)puts(ps);,*ps go back two positions everytime.
So I think t should be
z
xyz
Probably closer to what you want:
int main()
{
char str[]="xyz";
size_t length = sizeof(str)-1;
// size_t length = strlen(str); // safer version of above.
for (size_t i = 0; i < length; i++)
{
char* ps = str+length-i-1;
puts(ps);
}
}
"After while(*ps) ps++; *ps represents " ""
No, *ps is then '\0'.
When execute code for(ps--;ps-str>=0;ps--)puts(ps);, *ps go back two positions everytime
No, it does not. It starts by going back one step, then in each iteration it only goes back one step. It's the same as doing this:
{
ps--; // for(ps--; ...; ...)
while(ps-str >= 0) { // for(...; ps-str >= 0; ...)
puts(ps);
ps--; // for(...; ...; ps--)
}
}
ps-str>=0 is not a good test though. If you step ps "behind" the start of str the comparison is invalid.
A safe version could simply be:
#include <stdio.h>
int main() {
char str[] = "xyz", *ps = str;
while (*ps) ps++;
while (ps != str) {
--ps;
puts(ps);
}
}
I am trying to replace the last part of a string using a for backward for loop iterating for every element of the original string and assigning the first (last elements because I am iterating backwards in the for loop) elements to the string scl = "SCL_10m.tif", and the rest when the counter hits lower than 15, then get all the characters from the string string, and assign them to the newString.
However at the end the result is:
The old string was: S2_2018_08_09_B02_10m.tif
The new string is S2_2018_08_09_B0old string:
Which is different from my expected result:
The new string is S2_2018_08_09_SCL_10m.tif
I don't know what that happened. It supposed to iterate over all the elements of the newString Since it is the same size as the original string. I checked some replace string functions in C, but I wanted to implement something that helps me fast at this particular replace substring in String problem.
Dealing with String in C is very complicated and I am still learning some theory about it, such as: the null Byte and so on. Coming from JavaScript, Python, and Ruby where more of this functions are already implemented in some standard library, I find very hard and at the same time helpful to get the idea of how to implement such algorithms from scratch to deal with specific problems in my code.
I appreciate any idea or hint about what is happening in the code below:
/******************************************************************************
Replace last 11 characters in a longer string
by the values of a smaller (11-char long) string.
*******************************************************************************/
#include <stdio.h>
#include <string.h>
int main()
{
char *string;
string = "S2_2018_08_09_B02_10m.tif";
char *scl;
scl = "SCL_10m.tif";
int length = 0;
int length_scl = 0;
length_scl = strlen(scl);
length = strlen(string);
char newstring[length];
int i;
int cntr = length;
for (i = length; i >= 0; i--)
{
if(cntr > 15){
newstring[i] = scl[i];
cntr--;
}
else if(cntr <= 15)
{
newstring[i] = string[i];
}
}
printf("The old string was: %s\n", string);
printf("The new string is %s:\n", newstring);
return 0;
}
char *func1(char *new, const char *src, const char *repl)
{
size_t src_len, repl_len;
if(src && repl)
{
src_len = strlen(src);
repl_len = strlen(repl);
if(src_len >= repl_len)
{
new[src_len] = 0;
while(repl_len)
{
new[--src_len] = repl[--repl_len];
}
if(src_len)
{
while(--src_len)
{
new[src_len] = src[src_len];
}
}
}
}
return new;
}
char *func2(char *new, const char *src, const char *repl, size_t nchars)
{
//last nchars only (inluding the nul char)
size_t src_len, repl_len;
if(new &&src && repl)
{
new[--nchars] = 0;
src_len = strlen(src);
repl_len = strlen(repl);
if(src_len >= repl_len)
{
while(repl_len && nchars)
{
new[--nchars] = repl[--repl_len];
--src_len;
}
if(src_len && nchars)
{
while(--src_len && --nchars)
{
new[nchars] = src[src_len];
}
}
}
}
return new;
}
int main()
{
char *string = "S2_2018_08_09_B02_10m.tif";
char *repl = "SCL_10m.tif";
char new[256];
printf("func1 - new = \"%s\", src = \"%s\", repl = \"%s\"\n", func1(new, string, repl), string, repl);
printf("func2 - new = \"%s\", src = \"%s\", repl = \"%s\"\n", func2(new, string, repl, 15), string, repl);
printf("func2 - new = \"%s\", src = \"%s\", repl = \"%s\"\n", func2(new, string, "123456789_SCL_10m.tif", 15), string, repl);
return 0;
}
I have faced some problem when doing TDD.
I designed this function:
String *subString;
String *getWordAndUpdate(String *line, char *delimiter) {
String *word = malloc(sizeof(String));
int i;
stringLeftTrim(line);
word->length = 0;
word->startIndex = 0;
for(i = line->startIndex; i < line->length; i++) {
if(line->rawString[i] != ' ') {
word->rawString[i] = line->rawString[i];
line->startIndex++;
word->length++;
} else {
break;
}
}
line->length = line->length - i;
return word;
}
With my String struct:
typedef struct {
char *rawString;
int startIndex;
int length;
} String;
When I call this getWordAndUpdate function the first time it works fine, but when i call second time it says bad memory access.
extern String *subString;
void test_getWordAndUpdate_should_get_the_first_word_from_a_line_of_instruction() {
String oneLineString = {"movwf 0x10", 0, 10};
subString = getWordAndUpdate(&oneLineString, " ,;"); // works fine
TEST_ASSERT_EQUAL('m', subString->rawString[0]);
TEST_ASSERT_EQUAL('o', subString->rawString[1]);
TEST_ASSERT_EQUAL('v', subString->rawString[2]);
TEST_ASSERT_EQUAL('w', subString->rawString[3]);
TEST_ASSERT_EQUAL('f', subString->rawString[4]);
TEST_ASSERT_NOT_EQUAL(' ', subString->rawString[5]);
TEST_ASSERT_NOT_EQUAL('0', subString->rawString[6]);
TEST_ASSERT_NOT_EQUAL('x', subString->rawString[7]);
TEST_ASSERT_NOT_EQUAL('1', subString->rawString[8]);
TEST_ASSERT_NOT_EQUAL('0', subString->rawString[9]);
TEST_ASSERT_EQUAL(5, oneLineString.startIndex);
TEST_ASSERT_EQUAL(5, oneLineString.length);
TEST_ASSERT_EQUAL(0, subString->startIndex);
TEST_ASSERT_EQUAL(5, subString->length);
subString = getWordAndUpdate(&oneLineString, " ,;"); // bad memory access
}
You function getWordAndUpdate modify your object oneLineString in theses lines of code:
line->length--;
line->startIndex++;
So, when you call it a second times, your object in not consistent.
Try to make a copy of oneLineString or find an algo that not modify your parameter.
Maybe, you can use this kind of function:
String *subString;
String *getWordAndUpdate(String *line, char *delimiter) {
String *word = malloc(sizeof(String));
int i;
for (i = 0; line->rawString[i] != ' '; ++i)
word->rawString[i] = line->rawString[i];
word->length = i;
return word;
}
And you don't take care yet of your delimiter parameter.
Learning C and having many doubts.
I have a function (lets say function 1) that calls another function (lets say function 2).
Function 2 calculates an array of string.
How can I use this array in function 1?
Some code example:
int find_errors(char* word)
{
char error[100];
/*Given the word, It will find the duplicate chars and store it in the
error array. */
return 0;
}
int find_word(char* word)
{
find_errors (word);
printf("%s\n", error);
return 0;
}
There are at least three possible approaches:
Use a global variable
pass a parameter between them
return a pointer from the function
There are multiple ways to do this.
1) Create a dynamic array and return a pointer to the array. This will require you to manually free the memory for the array at a later time.
#define NUM_ELEMS 50
// In find_error():
char* error = malloc(NUM_ELEMS * sizeof(char));
return error;
// In find_word():
char *error = find_errors();
// do stuff
free(error);
2) Pass a pointer to find_errors that it can use as the error array. This will not require you to manually free the memory.
// In find_word():
char error[NUM_ELEMS];
find_error(error);
3) Use a global array. May make it more difficult for other people to understand your code. Has other potential problems as well.
// In global scope:
char error[NUM_ELEMS];
Your question relates to "call-by-reference" and "call-by-value".
char* getNewValsToSet(void)
{
char* new_vals = (char*) malloc(sizeof(char[5]));
new_vals[4] = '\0';
return new_vals;
}
void setValuesEven(char* vals_to_set)
{
vals_to_set[0] = 'A';
vals_to_set[2] = 'C';
}
void setValuesOdd(char* vals_to_set)
{
vals_to_set[1] = 'B';
vals_to_set[3] = 'D';
}
int main(void)
{
char* some_vals_to_set = getNewValsToSet();
setValsEven(some_vals_to_set);
setValsOdd(some_vals_to_set);
// ... now has vals "ABCD"
free(some_vals_to_set); //cleanup
return 0;
}
If you have "doubts" about learning C, IMHO it's one of the best things you can do (no matter the language in which you work) because it will explain exactly how things work "under-the-hood" (which all high-level languages try to hide to some degree).
You need to declare the error array globally and use it just like you did.
EDIT: using global variables isn't the best practice in most of the cases, like this one.
Here is an example of what you are looking for with an awesome console output. It dynamically allocates the array to hold any number errors (duplicate characters in your case) that may occur.
//Only free errors if result is > 0
int find_errors(char* word, char** errors)
{
int num_errors = 0;
int word_length = strlen(word);
int ARRAY_SIZE = MIN(8, word_length);
char existing[word_length];
int existing_index = 0;
*errors = NULL;
for(int i = 0; i < word_length; i++)
{
char character = word[i];
//Search array
for (int n = 0; n < word_length; ++n ) {
if(n >= existing_index)
{
existing[n] = character;
existing_index++;
break;
}
if (existing[n] == character) {
num_errors++;
if(!*errors)
*errors = (char*)malloc(ARRAY_SIZE * sizeof(char));
//Check if we need to resize array
if(num_errors >= ARRAY_SIZE)
{
ARRAY_SIZE *= 2;
ARRAY_SIZE = MIN(ARRAY_SIZE, word_length);
char *tmp = (char*)malloc(ARRAY_SIZE * sizeof(char));
memcpy(tmp, *errors, (unsigned long)ARRAY_SIZE);
free(*errors);
*errors = tmp;
}
//Set the error character
(*errors)[num_errors - 1] = character;
break;
}
}
}
return num_errors;
}
int find_word(char* word)
{
char* errors;
int errCount = find_errors (word, &errors);
if(errCount > 0)
{
printf("Invalid Characters: ");
for(int i =0; i < errCount; i++)
{
printf("%c ", errors[i]);
}
printf("\n");
free(errors);
}
return 0;
}
int main(int argc, char *argv[])
{
find_word("YWPEIT");
find_word("Hello World");
find_word("XxxxXXxXXoooooooOOOOOOOOOOOOOOOooooooooOOOOOOOOOOOOooooooOOO");
}
I am creating a function that will split a full unix filename(like /home/earlz/test.bin) into its individual parts. I have got a function, and it works for the first two parts perfect, but after that it produces erroneous output...
strlcpy_char will copy a string using term as the terminator, as well as 0.
If it is terminated with term, then term will be the last character of the string, then null.
returns trg string length...
int strlcpy_char(char *trg,const char *src,int max,char term){
int i;
if(max==0){return 0;}
for(i=0;i<max-1;i++){
if(*src==0){
*trg=0;
return i;
}
if(*src==term){
*trg=term;
trg++;
*trg=0; //null terminate
return i+1;
}
*trg=*src;
src++;
trg++;
}
*trg=0;
return max;
}
.
int get_path_part(char *file,int n,char *buf){
int i;
int current_i=0;
//file is assumed to start with '/'so it skips the first character.
for(i=0;i<=n;i++){
current_i++;
current_i=strlcpy_char(buf,&file[current_i],MAX_PATH_PART_SIZE,'/');
if(current_i<=1){ //zero length string..
kputs("!"); //just a debug message. This never happens with the example
return -1; //not enough parts to the path
}
}
if(buf[current_i-1]=='/'){
return 1; //is not the last part
}else{
return 0; //is the last part(the file part)
}
}
I use this code to test it:
kputs("test path: ");
kgets(cmd);
kputs("\n");
char *tmp=malloc(256);
int i=0;
get_path_part(cmd,i,tmp);
kputs(tmp);
kputs("\n");
i=1;
get_path_part(cmd,i,tmp);
kputs(tmp);
kputs("\n");
i=2;
get_path_part(cmd,i,tmp);
kputs(tmp);
kputs("\n");
When I try something like "/home/test.bin" it works right outputting
/home
/test.bin
But when I try "/home/earlz/test.bin" I get
/home
/earlz
/arlz
Anyone see the problem in my code, as I've been looking but I just can't see any problem.
Also, before you say "but there is a library for that" I am doing this in an operating system kernel, so I barely have a standard library. I only have parts of string.h and really that's about it for standard.
You overwrite current_i instead of adding it up as you walk through the path.
So
current_i++;
current_i=strlcpy_char(buf,&file[current_i],MAX_PATH_PART_SIZE,'/');
should really be
current_i += strlcpy_char(buf,&file[current_i+1],MAX_PATH_PART_SIZE,'/');
I think you need to track your current_i for i>1 since the max value returned from the strlcpy has no idea of where you are in the overall file string. does it make sense?
current_i=strlcpy_char(buf,&file[current_i],MAX_PATH_PART_SIZE,'/');
Don't you need to do something like
tocurrent_i += strlcpy_char...
instead of
tocurrent_i = strlcpy_char...
Does your code have to be re-entrant?
If not use strtok, it is in strings.h
STRTOK(P)
NAME
strtok, strtok_r - split string into tokens
SYNOPSIS
#include <string.h>
char *strtok(char *restrict s1, const char *restrict s2);
char *strtok_r(char *restrict s, const char *restrict sep,
char **restrict lasts);
Sorry for not commenting on your code though :)
If you are using Glib, g_strsplit is very nice and easy to use.
This is how I'd do it
char ** split_into_parts(char *path) {
char ** parts = malloc(sizeof(char *) * 100);
int i = 0;
int j = 0;
if (*path == '/') {
path++;
}
parts[0] = 0;
while (*path) {
if (*path == '/') {
parts[i][j] = 0;
i++;
parts[i] = 0;
j = 0;
} else {
if (parts[i] == 0) {
parts[i] = malloc(sizeof(char) * 100);
}
parts[i][j] = *path;
j++;
}
path++;
}
parts[i+1] = 0;
return parts;
}
Try something like the code I have below.
If you need implementations of standard C functions (like strchr()) try koders.com or just google for strchr.c.
#include <stdio.h>
#include <string.h>
const char *NextToken(const char *pStart, char chSep, char *pToken, size_t nTokMax)
{
const char *pEnd;
size_t nLength;
/* set output to empty */
*pToken=0;
/* make sure input is OK */
if (!pStart || *pStart!=chSep)
return NULL;
/* find end of token */
pEnd = strchr(pStart+1, chSep);
if (pEnd)
nLength = pEnd - pStart;
else
nLength = strlen(pStart);
if (nLength >= nTokMax) /* too big */
return NULL;
strncpy(pToken, pStart, nLength);
pToken[nLength] = 0;
return pEnd;
}
int main()
{
#define BUFFSIZE 256
char cmd[BUFFSIZE];
char tmp[BUFFSIZE];
const char *pStart=cmd;
int i=0;
puts("test path: ");
fgets(cmd, BUFFSIZE, stdin);
puts("");
do {
pStart = NextToken(pStart, '/', tmp, BUFFSIZE);
if (tmp[0])
puts(tmp);
} while (pStart);
return 0;
}