This question already has an answer here:
Comparing char* to string without strcmp
(1 answer)
Closed 2 years ago.
I should compare a struction with anothter without using strcmp(). But everytime the firstName on both sides are the same it doesn't go in the if function. I know the function gets the names bc in the printf I see clearly the names.
typedef struct{
char firstName[MAXC];
char familyName[MAXC];
char gender;
} TPerson;
....
int comparePeopleByFirstName(TPerson *a, TPerson *b){
if(a->firstName == b->firstName){
if(a->familyName < b->familyName){
return 1;
} else if (a->familyName > b->familyName){
return -1;
}
}else if(a->firstName < b->firstName){
return 1;
} else if (a->firstName > b->firstName){
return -1;
}
return 0;
}
In your example code, the structure contains arrays as members, not pointers. Therefore, it can never be the case that (a != b) && (a->firstName == b->firstname). It does not matter whether the contents of a->firstName and b->firstname match, because you are comparing the addresses of their first elements.
You could conceivably use memcmp() instead of strcmp() to perform the comparison, provided that you don't mind comparing the data after any string terminator, too. But maybe that would be cheating.
If you cannot use any library function then you'll need to compare char by char, with a loop. For example,
_Bool equal = 0;
for (int i = 0; ; ++i) {
if (a->firstName[i] != b->firstName[i]) {
// unequal
break;
}
if (a->firstName[i] == '\0') {
// b->firstName[i] == '\0' too, else control would not reach this point
equal = 1;
break;
}
}
That assumes properly terminated strings. If that's not a safe assumption then you can add a limit on i in the termination condition of the loop.
Related
I would like to use the following function to compare two char arrays:
if(strcmp((PtrTst->cDatVonCom),szGeraeteAntwort)==0)
Now my problem is that PtrTst->cDatVonCom[5000] is different than the szGeraeteAntwort[255] and the entire values looks a little bit different:
(abstract from the logfile).
PtrTst->cDatVonCom:
04/16/19 12:53:36 AB A{CR}{LF}
0 0{CR}{LF}
szGeraeteAntwort:
04/16/19 12:53:36 AB A 0 0{CR}{LF}
Could I check if the command (in this case AB A) is the same in both?
The command can change and it must be in both the same to go through the if statement.
UPDATE:
Both char arrays are always there and i need to check if the "szGeraeteAntwort" is in the PtrTst->cDatVonCom.
In C# i would use an cDatVonCom.Contains... or something like this to check if there the same.
You have two strings that whose logical content you want to compare, but their literal presentation may vary. In particular, there may be CR/LF line termination sequences inserted into one or both, which are not significant for the purposes of the comparison. There are many ways to approach this kind of problem, but one common one is to define a unique canonical form for your strings, prepare versions of both strings to that form, and compare the results. In this case, the canonical form would presumably be one without any CR or LF characters.
The most general way to approach this is to create canonicalized copies of your strings. This accounts for the case where you cannot modify the strings in-place. For example:
/*
* src - the source string
* dest - a pointer to the first element of an array that should receive the result.
* dest_size - the capacity of the destination buffer
* Returns 0 on success, -1 if the destination array has insufficient capacity
*/
int create_canonical_copy(const char src[], char dest[], size_t dest_size) {
static const char to_ignore[] = "\r\n";
const char *start = src;
size_t dest_length = 0;
int rval = 0;
while (*start) {
size_t segment_length = strcspn(start, to_ignore);
if (dest_length + segment_length + 1 >= dest_size) {
rval = -1;
break;
}
memcpy(dest + dest_length, start, segment_length);
dest_length += segment_length;
start += segment_length;
start += strspn(start, to_ignore);
}
dest[dest_length] = '\0';
return rval;
}
You might use that like so:
char tmp1[255], tmp2[255];
if (create_canonical_copy(PtrTst->cDatVonCom, tmp1, 255) != 0) {
// COMPARISON FAILS: cDatVonCom has more non-CR/LF data than szGeraeteAntwort
// can even accommodate
return -1;
} else if (create_canonical_copy(szGeraeteAntwort, tmp2, 255) != 0) {
// should not happen, given that szGeraeteAntwort's capacity is the same as tmp2's.
// If it does, then szGeraeteAntwort must not be properly terminated
assert(0);
return -1;
} else {
return strcmp(tmp1, tmp2);
}
That assumes you are comparing the strings for equality only. If you were comparing them for order, as well, then you could still use this approach, but you would need to be more care ful about canonicalizing as much data as the destination can accommodate, and about properly handling the data-too-large case.
A function that compares the strings while skipping over some characters could be used.
#include <stdio.h>
#include <string.h>
int strcmpskip ( char *match, char *against, char *skip) {
if ( ! match && ! against) { //both are NULL
return 0;
}
if ( ! match || ! against) {//one is NULL
return 1;
}
while ( *match && *against) {//both are not zero
while ( skip && strchr ( skip, *match)) {//skip not NULL and *match is in skip
match++;
if ( ! *match) {//zero
break;
}
}
while ( skip && strchr ( skip, *against)) {//skip not NULL and *against is in skip
against++;
if ( ! *against) {//zero
break;
}
}
if ( *match != *against) {
break;
}
if ( *match) {//not zero
match++;
}
if ( *against) {//not zero
against++;
}
}
return *match - *against;
}
int main( void) {
char line[] = "04/16/19 12:53:36 AB A\r\n 0 0\r\n";
char text[] = "04/16/19 12:53:36 AB A 0 0\r\n";
char ignore[] = "\n\r";
if ( strcmpskip ( line, text, ignore)) {
printf ( "do not match\n");
}
else {
printf ( "match\n");
}
return 0;
}
There are several things you can do; here are two:
Parse both strings (e.g. using scanf() or something more fancy)), and during the parsing ignore the newlines. Now you'll have the different fields (or an indication one of the lines can't be parsed properly, which is an error anyway). Then you can compare the commands.
Use a regular expression matcher on those two strings, to obtain just the command while ignoring everything else (treating CR and LF as newline characters essentially), and compare the commands. Of course you'll need to write an appropriate regular expression.
I'm trying various code to check Palindrome words, sure there are so many ways to code it, I somehow find something that triggers my curiosity but I couldn't find any answer somewhere although the code run good
That's found that there's a slight differences between two array of char wordReverse declaration below.
Could anyone give an explanation of these two declarations?
bool checkPallen(char word[]){
char wordReverse[25] = ""; //error if used char wordReverse[25];
int revCount = 0;
for(int i = strlen(word) - 1; i >= 0; i--){
wordReverse[revCount] = word[i]; //
revCount++;
}
if(strcmp(wordReverse, word) == 0) return true;
return false;
}
The difference is that uninitialized local variables have indeterminate values.
When you read from wordReverse,
strcmp(wordReverse, word)
strcmp takes two strings, i.e. it expects to find a NUL terminator somewhere.
Your loop that fills wordReverse doesn't terminate it, so you get undefined behavior here.
Fix:
wordReverse[revCount] = '\0';
after the loop.
The version that initializes wordReverse as
char wordReverse[25] = "";
works because it is equivalent to char wordReverse[25] = { '\0' }, which sets the first element to '\0' explicitly and all remaining elements to '\0' implicitly.
NB:
if (X) return true;
return false;
is equivalent to
return !!X; // Returns 1 if and only if X is not 0, and 0 otherwise
This question already has answers here:
Realloc fails after the 10th iteration inside a loop
(2 answers)
Closed 5 years ago.
I am trying to receive a string of unidentified length in C through pointers and realloc() function but after the string became 30 character long , the first few characters are like this :
ÿZ └
I am running it on windows :
#include <stdio.h>
#include <stdlib.h>
char* array;
int current = 0;
int size = 10;
void add(char element)
{
if (current == size) {
size += 10;
realloc(array, size * (sizeof(char)));
}
*(array + current) = element;
current++;
}
int main()
{
array = calloc(10, sizeof(char));
char c;
loop:
c = getchar();
if (c != '\n') {
add(c);
goto loop;
}
else {
for (int i = 0; i <= current - 1; i++) {
putchar(*(array + i));
}
printf("\nThe size of the string is %d", current);
}
}
You are not storing the return value of realloc.
char *temp;
temp=realloc(array,size*(sizeof(char)));
if( temp )
array = temp;
else
// error
goto makes code harder to debug by generating a complex control flow.
If you think, you will see you can replace goto with a for or while loop too.
You can see that your else part is not part of the goto part. Once else is executed it's never going to execute again.
So create a loop with this(else part) outside the loop.
Also return type of getchar() is int.
You need to do like this:
array=realloc(array,size*(sizeof(char)));
The memory may be moved to another location. That's why you need to reassign the pointer.
Of course, it is good to do some error checking too:
char *tmp;
tmp = realloc(array,size*(sizeof(char)));
if(tmp)
array=tmp;
else
perror("realloc failed");
I'm trying to make a quick function that gets a word/argument in a string by its number:
char* arg(char* S, int Num) {
char* Return = "";
int Spaces = 0;
int i = 0;
for (i; i<strlen(S); i++) {
if (S[i] == ' ') {
Spaces++;
}
else if (Spaces == Num) {
//Want to append S[i] to Return here.
}
else if (Spaces > Num) {
return Return;
}
}
printf("%s-\n", Return);
return Return;
}
I can't find a way to put the characters into Return. I have found lots of posts that suggest strcat() or tricks with pointers, but every one segfaults. I've also seen people saying that malloc() should be used, but I'm not sure of how I'd used it in a loop like this.
I will not claim to understand what it is that you're trying to do, but your code has two problems:
You're assigning a read-only string to Return; that string will be in your
binary's data section, which is read-only, and if you try to modify it you will get a segfault.
Your for loop is O(n^2), because strlen() is O(n)
There are several different ways of solving the "how to return a string" problem. You can, for example:
Use malloc() / calloc() to allocate a new string, as has been suggested
Use asprintf(), which is similar but gives you formatting if you need
Pass an output string (and its maximum size) as a parameter to the function
The first two require the calling function to free() the returned value. The third allows the caller to decide how to allocate the string (stack or heap), but requires some sort of contract about the minumum size needed for the output string.
In your code, when the function returns, then Return will be gone as well, so this behavior is undefined. It might work, but you should never rely on it.
Typically in C, you'd want to pass the "return" string as an argument instead, so that you don't have to free it all the time. Both require a local variable on the caller's side, but malloc'ing it will require an additional call to free the allocated memory and is also more expensive than simply passing a pointer to a local variable.
As for appending to the string, just use array notation (keep track of the current char/index) and don't forget to add a null character at the end.
Example:
int arg(char* ptr, char* S, int Num) {
int i, Spaces = 0, cur = 0;
for (i=0; i<strlen(S); i++) {
if (S[i] == ' ') {
Spaces++;
}
else if (Spaces == Num) {
ptr[cur++] = S[i]; // append char
}
else if (Spaces > Num) {
ptr[cur] = '\0'; // insert null char
return 0; // returns 0 on success
}
}
ptr[cur] = '\0'; // insert null char
return (cur > 0 ? 0 : -1); // returns 0 on success, -1 on error
}
Then invoke it like so:
char myArg[50];
if (arg(myArg, "this is an example", 3) == 0) {
printf("arg is %s\n", myArg);
} else {
// arg not found
}
Just make sure you don't overflow ptr (e.g.: by passing its size and adding a check in the function).
There are numbers of ways you could improve your code, but let's just start by making it meet the standard. ;-)
P.S.: Don't malloc unless you need to. And in that case you don't.
char * Return; //by the way horrible name for a variable.
Return = malloc(<some size>);
......
......
*(Return + index) = *(S+i);
You can't assign anything to a string literal such as "".
You may want to use your loop to determine the offsets of the start of the word in your string that you're looking for. Then find its length by continuing through the string until you encounter the end or another space. Then, you can malloc an array of chars with size equal to the size of the offset+1 (For the null terminator.) Finally, copy the substring into this new buffer and return it.
Also, as mentioned above, you may want to remove the strlen call from the loop - most compilers will optimize it out but it is indeed a linear operation for every character in the array, making the loop O(n**2).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *arg(const char *S, unsigned int Num) {
char *Return = "";
const char *top, *p;
unsigned int Spaces = 0;
int i = 0;
Return=(char*)malloc(sizeof(char));
*Return = '\0';
if(S == NULL || *S=='\0') return Return;
p=top=S;
while(Spaces != Num){
if(NULL!=(p=strchr(top, ' '))){
++Spaces;
top=++p;
} else {
break;
}
}
if(Spaces < Num) return Return;
if(NULL!=(p=strchr(top, ' '))){
int len = p - top;
Return=(char*)realloc(Return, sizeof(char)*(len+1));
strncpy(Return, top, len);
Return[len]='\0';
} else {
free(Return);
Return=strdup(top);
}
//printf("%s-\n", Return);
return Return;
}
int main(){
char *word;
word=arg("make a quick function", 2);//quick
printf("\"%s\"\n", word);
free(word);
return 0;
}
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 11 years ago.
A friend of mine was asked the following question a Yahoo interview:
Given a string of the form "abbccc" print "a1b2c3". Write a function that takes a string and return a string. Take care of all special cases.
How would you experts code it?
Thanks a lot
if (0==strcmp(s, "abbccc"))
return "a1b2c3";
else
tip_the_interviewer(50);
Taken care of.
There's more than one way to do it, but I'd probably run over the input string twice: once to count how many bytes are required for the output, then allocate the output buffer and go again to actually generate the output.
Another possibility is to allocate up front twice the number of bytes in the input string (plus one), and write the output into that. This keeps the code simpler, but is potentially very wasteful of memory. Since the operation looks like a rudimentary compression (RLE), perhaps it's best that the first implementation doesn't have the output occupy double the memory of the input.
Another possibility is to take a single pass, and reallocate the output string as necessary, perhaps increasing the size exponentially to ensure O(N) overall performance. This is quite fiddly in C, so probably not the initial implementation of the function, especially in interview conditions. It's also not necessarily any faster than my first version.
However it's done, the obvious "special case" is an empty input string, because the obvious (to me) implementation will start by storing the first character, then enter a loop. It's also easy to write something where the output may be ambiguous: "1122" is the output for the input "122", but perhaps it is also the output for the input consisting of 122 1 characters. So you might want to limit run lengths to at most 9 characters (assuming base 10 representation) to prevent ambiguity. It depends what the function is for - conjuring a complete function specification from a single example input and output is not possible.
There's also more than one way to design the interface: the question says "returns a string", so presumably that's a NUL-terminated string in a buffer newly-allocated with malloc. In the long run, though, that's not always a great way to write all your string APIs. In a real project I would prefer to design a function that takes as input the string to process, together with a pointer to an output buffer and the length of that buffer. It returns either the number of bytes written, or if the output buffer isn't big enough it returns the number which would have been written. Implementing the stated function using this new function is easy:
char *stated_function(const char *in) {
size_t sz = new_function(in, NULL, 0);
char *buf = malloc(sz);
if (buf) new_function(in, buf, sz);
return buf;
}
I'm also confused what "print" means in the question - other answerers have taken it to mean "write to stdout", meaning that no allocation is necessary. Does the interviewer want a function that prints the encoded string and returns it? Prints and returns something else? Just returns a string, and is using "print" when they don't really mean it?
Follow the following algo and implement it.
Run a loop for all the letters in
string.
Store the first character in a temp
char variable.
For each change in character
initialize a counter with 1 and
print the count of previous
character and then the new letter.
This smells like a homework question, but the code was just too much fun to write.
The key ideas:
A string is a (possibly empty) sequence of nonempty runs of identical characters.
Pointer first always points to the first in a run of identical characters.
After the inner while loop, pointer beyond points one past the end of a run of identical characters.
If the first character of a run is a zero, we've reached the end of the string. The empty string falls out as an instance of the more general problem.
The space required for a decimal numeral is always at most the length of a run, so the result needs at most double the memory. The code works fine with a run length of 53: valgrind reports no memory errors.
Pointer arithmetic is beautiful.
The code:
char *runcode(const char *s) {
char *t = malloc(2 * strlen(s) + 1); // eventual answer
assert(t);
char *w = t; // writes into t;
const char *first, *beyond; // mark limits of a run in s
for (first = s; *first; first = beyond) { // for each run do...
beyond = first+1;
while (*beyond == *first) beyond++; // move to end of run
*w++ = *first; // write char
w += sprintf(w, "%d", beyond-first); // and length of run
}
*w = '\0';
return t;
}
Things I like:
No auxiliary variable for the character whose run we're currently scanning.
No auxiliary variable for the count.
Reasonably sparing use of other local variables.
As others have pointed out, the spec is ambiguous. I think that's fine for an interview question: the point may well be to see what the job applicant does in an ambiguous situation.
Here's my take on the code. I've made some assumptions (since I can't very well ask the interviewer in this case):
This is a simple form of run-length encoding.
Output is of the form {character}{count}.
To avoid ambiguity, the count is 1..9.
Runs of the same character longer than 9 are split into multiple counts.
No dynamic allocation is done. In C, it's usually better to let caller take care of that. We return true/false to indicate if there was enough space.
I hope the code is clear enough to stand on its own. I've included a test harness and some test cases.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void append(char **output, size_t *max, int c)
{
if (*max > 0) {
**output = c;
*output += 1;
*max -= 1;
}
}
static void encode(char **output, size_t *max, int c, int count)
{
while (count > 9) {
append(output, max, c);
append(output, max, '0' + 9);
count -= 9;
}
append(output, max, c);
append(output, max, '0' + count);
}
static bool rle(const char *input, char *output, size_t max)
{
char prev;
int count;
prev = '\0';
count = 0;
while (*input != '\0') {
if (*input == prev) {
count++;
} else {
if (count > 0)
encode(&output, &max, prev, count);
prev = *input;
count = 1;
}
++input;
}
if (count > 0)
encode(&output, &max, prev, count);
if (max == 0)
return false;
*output = '\0';
return true;
}
int main(void)
{
struct {
const char *input;
const char *facit;
} tests[] = {
{ "", "" },
{ "a", "a1" },
{ "aa", "a2" },
{ "ab", "a1b1" },
{ "abaabbaaabbb", "a1b1a2b2a3b3" },
{ "abbccc", "a1b2c3" },
{ "1", "11" },
{ "12", "1121" },
{ "1111111111", "1911" },
{ "aaaaaaaaaa", "a9a1" },
};
bool errors;
errors = false;
for (int i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) {
char buf[1024];
bool ok;
ok = rle(tests[i].input, buf, sizeof buf);
if (!ok || strcmp(tests[i].facit, buf) != 0) {
printf("FAIL: i=%d input=<%s> facit=<%s> buf=<%s>\n",
i, tests[i].input, tests[i].facit, buf);
errors = true;
}
}
if (errors)
return EXIT_FAILURE;
return 0;
}
int priya_homework(char *input_str, char *output_str, int out_len)
{
char pc,c;
int count=0,used=0;
/* Check for NULL and empty inputs here and return*/
*output_str='\0';
pc=*input_str;
do
{
c=*input_str++;
if (c==pc)
{
pc=c;
count++;
}
else
{
used=snprintf(output_str,out_len,"%c%d",pc,count);
if (used>=out_len)
{
/* Output string too short */
return -1;
}
output_str+=used;
out_len-=used;
pc=c;
count=1;
}
} while (c!='\0' && (out_len>0));
return 0;
}
Damn, thought you said C#, not C. Here is my C# implementation for interest's sake.
private string Question(string input)
{
var output = new StringBuilder();
while (!string.IsNullOrEmpty(input))
{
var first = input[0];
var count = 1;
while (count < input.Length && input[count] == first)
{
count++;
}
if (count > input.Length)
{
input = null;
}
else
{
input = input.Substring(count);
}
output.AppendFormat("{0}{1}", first, count);
}
return output.ToString();
}
Something like this:
void so(char s[])
{
int i,count;
char cur,prev;
i = count = prev = 0;
while(cur=s[i++])
{
if(!prev)
{
prev = cur;
count++;
}
else
{
if(cur != prev)
{
printf("%c%d",prev,count);
prev = cur;
count = 1;
}
else
count++;
}
}
if(count)
printf("%c%d",prev,count);
printf("\n");
}