C++: error: lvalue required as left operand of assignment - c

I receive the error in the title when I try to run this code:
//Copies the information from one array to another until a set length using pointers
void strncpy2(char* t, const char* s, const unsigned int n)
{
unsigned int i;
for (i = 0; i < n /* This i < n causes the error */ && *t++ = *s++; i++);
*(t + i) = '\0';
}
When I take out the i < n it works fine, and when I move the i < n to the right of the *t++ = *s++ I get no compiling error, however the code doesn't work as intended.
What's going on here? I appreciate any help. Thank you!

You need parentheses around the assignment in the loop, since the && operator has higher precedence than the assignment. Try this:
for (i = 0; i < n && (*t++ = *s++); i++);

The semantic of your call is not clear, especially it differs significantly from strncpy().
You seem to manipulate raw string but you don't check for the end of string, which is unsafe.
Moreover the assignment after the loop uses "t" as a base pointer, which is wrong since you modified it.
I don't know what "n" implies on the size of t, if t has to be at least size n, you have to stop iterating at n-2 or your final assignment is out-of-bound.
Finally I stay away from codes that have side effects in the for loop header.
void strncpy2(char* t, const char* s, const unsigned int n)
{
unsigned int i;
for (i = 0; i < n-1; i++) {
t[i] = s[i];
if(s[i] == '\0') return;
}
t[i] = '\0';
}
if you want to use pointers chasing (c):
void strncpy2(char* t, const char* s, const unsigned int n)
{
unsigned int i;
for (i = 0; i < n-1; i++) {
*t = *s;
if(*s == '\0') return;
t++; s++;
}
*t = '\0';
}
Now I don't know what is the point of doing that, already having strncpy() and memcpy() in the standard library. And of course, C++ code should avoid raw string ;)

Related

Difference b/w using i<strlen() and str[i] != '\0'

When I use for(i=0;i<strlen(s);i++) then I am getting time limit exceed error. And When I use for(i=0;s[i]!='\0';i++) my code get successful submit. Why?
I am also providing link of question from codechef - https://www.codechef.com/problems/LCPESY
Type 1:
for (i = 0; i < strlen(s1); i++) {
f1[s1[i]]++;
}
for (i = 0; i < strlen(s2); i++) {
f2[s2[i]]++;
}
Type 2:
for (i = 0; s1[i] != '\0'; i++) {
f1[s1[i]]++;
}
for (i = 0; s2[i] != '\0'; i++) {
f2[s2[i]]++;
}
Complete code:
#include <stdio.h>
#include <string.h>
long int min(long int a, long int b) {
if (a >= b)
return b;
else
return a;
}
int main(void) {
// your code goes here
int t;
scanf("%d", &t);
while (t--) {
char s1[10001], s2[10001];
scanf("%s%s", s1, s2);
long int f1[200] = { 0 }, f2[200] = { 0 }, i, count = 0;
for (i = 0; i < strlen(s1); i++) {
f1[s1[i]]++;
}
for (i = 0; i < strlen(s2); i++) {
f2[s2[i]]++;
}
for (i = 0; i < 200; i++) {
count += min(f1[i], f2[i]);
}
printf("%ld\n", count);
}
return 0;
}
If a non-optimizing compiler is used it can be that strlen is re-evaluated once per each iteration. strlen then needs to check each and every character in the string for equivalence with 0. This results in quadratic runtime, where there are O(n²) checks for the terminatin null instead of just the necessary O(n) times. In the strlen code the timeout happens because it does perhaps 2,000,000 null checks and 10,000 other operations; the other code would do 2,000 null checks and those same 10,000 other operations and not time out.
However, this need not be a case. Due to the as-if rule, a C compiler can generate exactly equivalent machine for the cases
for (i = 0; i < strlen(s1); i++){
f1[s1[i]] ++;
}
and
for (i = 0; s1[i] != '\0'; i++) {
f1[s1[i]] ++;
}
because a compiler can easily prove that the inner loop cannot possibly change s1 and therefore both forms would behave equivalently.
In addition to #Antti Haapala good answer:`
Difference b/w using i<strlen() and str[i] != '\0'
Code like int i; ... i < strlen(s1) readily complains about mismatched sign-ness - when such warnings are enabled. Usually inoffensive code like that discourages wide use of that warning. I see that as a less preferred approach. str[i] != '\0' does not cause that warning.
Some other concerns
Prevent buffer overflow
char s1[10001], s2[10001];
// scanf("%s%s", s1, s2);
if (scanf("%10000s%10000s", s1, s2) == 2) {
// OK, success, lets go!
There are more than 200 characters.
// long int f1[200] = { 0 };
long int f1[256] = { 0 };
// or better
long int f1[UCHAR_MAX + 1] = { 0 };
Avoid a negative index
// f1[s1[i]]++;
f1[(unsigned char) s1[i]]++;
or use unquestionable unsigned types.
// char s1[10001];
unsigned char s1[10001];

Extracting a portion of an array by using pointer in C

For example if I have an array and I want to extract elements of this array with a specified value as a new array. I did as the following:
int a[10] = { 1, 2, 1, 3, 2, 3, 4, 1, 2, 6 };
int i, k;
int count = 0;
for (i = 0; i < 10; i++) {
if (a[i] == 1) {
count = count + 1;
}
}
int b[count];
k = 0;
for (i = 0; i < 10; i++) {
if (a[i] == 1) {
b[k] = a[i];
k = k + 1;
}
}
So, for the array "a" I extracted all the elements of value 1, and make them as a new array "b". How can I achieve the same thing by using pointers? Will it be conciser than this way? If it is possible, is there any other advantages?
I think you already noticed that you just had to write 1 several times; yet I suppose you want that it works for arbitrary conditions.
"Using a pointer" can mean dynamic memory allocation instead of a variable length array. Just for the sake of having use a pointer, you could then write:
int *b = malloc(count * sizeof(int));
k = 0;
for (i = 0; i < 10; i++) {
if (a[i] == 1) {
b[k] = a[i];
k = k + 1;
}
}
If, just for sake of using a pointer for the writing process, too, you could adapt the program as follows:
int *b = malloc(count * sizeof(int));
int *bPtr = b;
for (i = 0; i < 10; i++) {
if (a[i] == 1) {
*bPtr++ = a[i];
}
}
Hope it helps a bit.
If you don't know which portion of the array your target values will be in, as in your case, where you're searching the entire unsorted array for a specific value, then there is no advantage to using pointers rather than a linear search to find the elements in the array you are after.
If, however, you are trying to access or copy a contiguous set of elements starting at a known index in the array, then you could use a pointer to simplify things. For example, if I'm after the last few elements in an array of chars, this works:
#include <stdio.h>
int main()
{
char str[100] = "I don\'t want anyone to think I hate the Calgary Flames";
char *c = (str + 29);
printf("%s\n", c);
return 0;
}
Output:
I hate the Calgary Flames
In this case, no, there is no benefit. a[i] is already basically a + (sizeof(int) * i). Even if you used pointers, you'd still have to do all the counting anyway to make sure you don't walk off the end of the array.
Where its often handy is with a null terminated array of pointers, such as a string, where you don't know the length. But it's not really about performance. As you can see below, they have to do roughly the same things.
char string[] = "foo bar";
// Allocate and initialize i.
// `string + i` twice, compare, increment.
for( int i = 0; string[i] != '\0'; i++ ) {
printf("%c", string[i]);
}
puts("");
// Allocate and initialize s.
// Dereference s twice, compare, increment.
for( char *s = string; *s != '\0'; s++ ) {
printf("%c", *s);
}
puts("");
Where iterating by pointer is handy is when you need to iterate through an array in several steps. Instead of passing around the original array pointer plus your last index, and changing all your function signatures to accommodate, just pass around the incremented pointer and return the incremented pointer. This allows you to use standard string functions on the middle of a string.
#include <stdio.h>
char *findVal( char *string, char delim ) {
char *val = string;
for( ; *val != '\0' && *val != delim; val++ ) {
}
if( val == '\0' ) {
return NULL;
}
else {
// val is sitting on the ':'
return val+1;
}
}
int main() {
char string[] = "this:that";
char *val = findVal(string, ':');
if( val != NULL ) {
// Just use val, not string[valIdx].
printf("%s\n", val);
}
}
This is also safer. With an offset there's two things which must remain in sync, the pointer and the offset; that opens the possibility that the wrong offset will be used with the wrong pointer. An incremented pointer carries its offset with it.
As has been pointed out in the comments, you can tighten up the second loop like so:
int b[count];
for (i = 0; i < count; i++) {
b[i] = 1;
}

Any issues with the following in-place reverse function?

I wrote this following in-place reverse function and it works fine.
However, when I googled for a solution, I found plethora of more complex solutions but nothing this simple. Will the following not work for certain inputs or has some performance issues?
void reverse(char* str) {
int n = strlen(str);
char temp;
for (int i=0; i<n/2; i++) {
temp = str[i];
str[i] = str[n-i-1];
str[n-i-1] = temp;
}
}
int main() {
char input[] = "Reverse Me!";
reverse(input);
return 0;
}
Yes. This may work correctly on your system; however, strlen returns size_t, which might have a greater precision than int, resulting in only a part (or none?) of the actual string being reversed. That's an easy fix: Declare n as a size_t instead of an int.
Your solution could be simpler, if you were to decrease n each iteration while you're increasing x. Then you wouldn't need as much of the subtraction logic, or any of the division logic.
void reverse(char *str) {
for (size_t x = 0, y = strlen(str); y --> x; x++) {
char temp = str[x];
str[x] = str[y];
str[y] = temp;
}
}
No, there are no issues with your code. It will work perfectly in any situation with ASCII characters.
#Rahat Mahbub is right about size_t. On many 64 bit machines, your algorithm will fail for strings 2^31 in length or longer. Using size_t will prevent that.
But the main problem is the complexity. A clearer code is something like:
void reverse(char *str) {
if (*p == '\0') return;
for (size_t i = 0, j = strlen(str) - 1; i < j; ++i, --j) {
char tmp = str[i];
str[i] = str[j];
str[j] = tmp;
}
}
In words, place i at the start of the string and j at the end. Swap characters they index and move both toward the middle of until they touch.
With pointers, it's even a bit more succinct:
void reverse(char *p) {
if (*p == '\0') return;
for (char *q = p + (strlen(p) - 1); p < q; ++p, --q) {
char tmp = *p;
*p = *q;
*q = tmp;
}
}
Unfortunately as #chux pointed out, you need the if or some other footwork to avoid computing q = p - 1 on empty input, which is not a valid pointer. In the indexed version, you need it because size_t is an unsigned type; it has no -1 value.

Help with reversing a string in C

I am trying to reverse a character string in C
Here is what I have
void reverse(char str[]) {
int i = 0;
int length;
// Get string length
for (i = 0; str[i] != '\0' ; ++i) {
length = i;
}
char reversed[1000];
int j;
j = 0;
// Reverse it
for (j = 0; j < length ; ++j) {
reversed[j] = str[length - j];
}
}
I know that reversed contains the string reversed, but I'm not sure how to modify the original str without throwing away data I need.
I also don't know how to set strto reversed without looping again.
Would it be acceptable to do another...
int m;
m = 0;
for (m = 0; m < length ; ++m) {
str[j] = reversed[j];
}
Usually I'd say this many loops smells, but I'm also still quite unfamiliar with the language so I'm not sure...
Update
Thanks for all the answers guys, and I appreciate the edits too!
I ended up going with this...
int main() {
char str[] = "Reverse me!";
int length;
for (length = 0; str[length] != '\0'; length++) {
}
printf("length => %d chars\n", length);
int j, k;
char c;
for (j = 0, k = length - 1; j < k; j++, k--) {
c = str[k];
str[k] = str[j];
str[j] = c;
}
printf("reversed => %s\n", str);
return 0;
}
Some things I now know...
There is a strlen() like in PHP. However, it has not been discussed in the book yet, plus I need to get familiar with null terminated strings.
A for loop can assign and do multiple things that are comma separated. I never knew this!
So asking was worthwhile :)
You want to do an in-place reversal. Here's a standard algorithm:
// taken from The C Programming Language
// by Brian Kernighan and Dennis Ritchie (K&R)
void reverse(char s[])
{
int c, i, j;
for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
Note that strlen pretty much replaces your original first loop. It's one of the many standard string manipulation routines available from string.h.
See also
Wikipedia/In-place algorithm
Wikipedia/string.h
Wikipedia/C Standard Library
You can use either of the two methods below, depending on whether you're comfortable with pointers or not. It will also be worthwhile looking at them side-by-side when you satrt learning about pointers so you can better understand how they map to each other.
This is a full program for testing purposes:
#include <stdio.h>
#include <string.h>
// The pointer version.
void reverse1 (char *str) {
char t; // Temporary char for swapping.
char *s = str; // First character of string.
char *e = &(s[strlen(s)-1]); // Last character of string.
// Swap first and last character the move both pointers
// towards each other. Stop when they meet or cross.
while (s < e) {
t = *s;
*s++ = *e;
*e-- = t;
}
}
// The array version.
void reverse2 (char *str) {
char t; // Temporary char for swapping.
int s = 0; // First character of string.
int e = strlen(str)-1; // Last character of string.
// Swap first and last character the move both pointers
// towards each other. Stop when they meet or cross.
while (s < e) {
t = str[s];
str[s++] = str[e];
str[e--] = t;
}
}
int main (void) {
char x[] = "This is a string for reversing.";
printf ("Original: [%s]\n", x);
reverse1 (x);
printf ("Reversed: [%s]\n", x);
reverse2 (x);
printf (" Again: [%s]\n", x);
return 0;
}
and the output is:
Original: [This is a string for reversing.]
Reversed: [.gnisrever rof gnirts a si sihT]
Again: [This is a string for reversing.]
Comments on your code:
void reverse(char str[]) {
int i = 0;
int length;
// Get string length
for (i = 0; str[i] != '\0' ; ++i) {
length = i;
}
Rather than copying the i to length every time you could just wait until the end.
size_t len = 0; // size_t is an unsigned integer that is large enough to hold the sizes
// of the biggest things you can have (32 bits on 32 bit computer,
// 64 bits on a 64 bit computer)
char * s = str;
while (*s) {
len++;
s++;
}
Though the compiler would probably be able to make this optimization for you.
You should know, though, that there is a standard string function strlen ( #include <string.h> )which will measure the length of a char string using the same general algorithm (look for the end) but is usually optimized for the target processor.
len = strlen(str);
Your code again:
char reversed[1000];
Using big arrays are good for learning and simple examples, but you can also allocate memory dynamically based on the size you now know you need. The standard function for doing this is malloc which is in stdlib.h (also in malloc.h). Memory allocated with this function should also be freed, though.
int * p = malloc( 8 * sizeof(int) ); // allocate an array of 8 ints
/* ... work on p ... */
free(p);
/* ... don't access the memory pointed to by p anymore ... */
p = 0;
There are also other functions in the malloc family. There's calloc, which allocates memory and clears sets it to 0. There is also a function called strdup (which isn't in standard C, but is very widely available in string.h) which takes a string and allocates a duplicate of it. It is really just:
char * strdup(const char * str) {
size_t len = strlen(str);
char * s = malloc(len+1);
if (!s) {
return s;
}
return strcpy(s,str); // This could have been memcpy since you know the size
// and memcpy might have been faster on many processors
}
Another useful memory allocation function is alloca (not in the C standard, but widely available and similar functionality is available with variable length arrays in C99). It is great, but works differently from malloc. It allocates memory that is only useable until the current function returns because this memory is allocated in the same way as memory for local variables (from the stack).
More of your code:
int j;
j = 0;
// Reverse it
for (j = 0; j < length ; ++j) {
reversed[j] = str[length - j];
}
The code:
void reverse_in_place(char * str, size_t len) {
size_t i, j;
for (i = 0, j = len - 1; i < j ; i++, j--) {
char a = str[i];
char z = str[j];
str[i] = z;
str[j] = a;
}
}
should swap the order of the string without making a copy of it. For strings with odd length it won't try to swap the middle char with itself.
Reversing a string in C using pointers
#include<stdio.h>
char *srcptr = "Hello!";
char *destptr;
unsigned int length = 0;
void main(void)
{
while(*(ptr++) != '\0')
{
length++;
}
//at the end of while loop, pointer points to end of string
while(length--)
{
*destptr++ = *ptr--;
}
//append null at the end
*destptr = '\0';
printf("%s",ptr);
}

Segmentation fault on little function

I keep getting a segmentation fault on this one, does someone see the reason?
void str_sort(char s[]) {
int i, j;
char c;
for (i = strlen(s) - 1; i > 0; i--)
for (j = 0; j < i; j++)
if (*(s+j) > *(s+j+1)) {
c = *(s+j);
*(s+j) = *(s+j+1);
*(s+j+1) = c;
}
return;
}
String literals are stored in a region of memory that disallows modifications. If you create an array to store the string instead, it should work fine (assuming your function is correct which it looked like at first glance):
int main()
{
char str[] = "PC-spiel";
str_sort(str);
return 0;
}
The difference is a string literal like "PC-spiel" is a pointer to a non-modifiable constant. But the string str is located on the stack like a normal array/variable and gets the value "PC-spiel" copied into it at runtime.
Your string sorting function operates in place. It will modify its string argument. It you call it with a string literal, trying to modify the argument will invoke undefined behavior. If the string literal is already sorted such as "abc", no problem since no write access is performed, but if you call str_sort("ba"); undefined behavior ensues and a crash is a possible form of undefined behavior.
Note that you should use the index notation for better readability and the final return; is useless:
void str_sort(char s[]) {
int i, j;
char c;
for (i = strlen(s) - 1; i > 0; i--) {
for (j = 0; j < i; j++) {
if (s[j] > s[j+1]) {
c = s[j];
s[j] = s[j+1];
s[j+1] = c;
}
}
}
}

Resources