Swapping strings WITHOUT using double pointers - c

This is actually just a small part of the original assignment I have in algorithms and data structure. At some point I'm supposed to write a function that swaps two elements in an array of strings.
The prototype we have to use is:
void swap(char *a, char *b);
To me it makes much more sense passing double pointers to this function (if swapping strings). In fact, I don't know how to make their prototype work without using double pointers. Am I missing something or is this wrong?
I've done my research on this a while ago and there are many answered questions here, I'm just wondering whether the person who was designing this assignment made a mistake.

You can swap two strings by creating a temporary char array of length equal to either one of the two strings, and by using strcpy().
Of course, you need to make sure that swapping does not overflow one of the two strings/arrays. Here is a sample example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void swap(char *a, char *b)
{
char *tmp = malloc(strlen(a) + 1);
strcpy(tmp, a);
strcpy(a, b);
strcpy(b, tmp);
free(tmp);
}
int main(void)
{
char str_a[50] = "Hello world";
char str_b[50] = "What's up";
swap(str_a, str_b);
puts(str_a);
puts(str_b);
return 0;
}
Another approach is to use a loop with a single char variable, thus avoiding dynamic memory allocation:
void swap(char *a, char *b)
{
char tmp;
while (*a && *b)
{
tmp = *a;
*a++ = *b;
*b++ = tmp;
}
if (!*a)
{
size_t n = 0;
while (b[n])
{
*a++ = b[n++];
}
}
else if (!*b)
{
size_t n = 0;
while (a[n])
{
*b++ = a[n++];
}
}
*a = '\0';
*b = '\0';
}

Related

How to sort an array of pointers in alphabetical order, and then use qsort?

I am trying to write a function in which I sort the pointers inside of wptrs, an array of pointers to strings in another array. I am challenging myself not to use string.h for this exercise, as I want to understand how a sorting algorithm could work in C. I am using qsort(), however, but I am trying to write a comparison function for it called mycharptrcompare().
I have looked at how strcmp() works, and I have tried to mimic that with mycharptrcompare(). However, I notice the difference that strcmp() expects a char*, while the mycharptrcompare() function expects a char**. I've written a method called dumpwptrs to show me the contents and how they are organized within wptrs. Thus far, I have the following code:
UPDATE:
I have also tried:
int mycharptrcompare(const void *a, const void *b)
{
//Need to convert a void * to a more specific type to dereference
const char *aPtr = a;
const char *bPtr = b;
const char **pa = &aPtr;
const char **pb = &bPtr;
while (*pa && *pa == *pb) {
pa++;
pb++;
}
return *pa - *pb;
}
and my output I got was:
(null)
jumps
world
is
dog
blue
Which is still incorrect, because my list should be sorted in alphabetical order, and the first input (the word "hello"), has not been read in.
FYI here is an example use of qsort().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int cmp(const void *a, const void *b)
{
const char **pa = a;
const char **pb = b;
return strcmp(*pa, *pb);
}
int main(void)
{
char *wptrs[] = { "hello", "jumps", "world", "is", "dog", "blue" };
size_t len = sizeof wptrs / sizeof wptrs[0];
qsort(wptrs, len, sizeof wptrs[0], cmp);
for(size_t i = 0; i < len; i++) {
printf("%s\n", wptrs[i]);
}
return 0;
}
Program output:
blue
dog
hello
is
jumps
world

Swap without worrying about the data type

Is that implementation valid and safe to swap two array or variable without worrying about their data type? Or should I use a function pointer?.
This type of code is focusing about using a good implementation of void pointers to swap without worring about the data type.
#include <stdio.h>
#include <string.h>
void swap(void *, void *, int);
int main(void) {
char a[] = "home";
char b[] = "door";
printf("%s %s\n", a, b);
swap(&a, &b, sizeof(a));
printf("%s %s \n", a, b);
return 0;
}
void swap( void *a, void *b, int siz){
char buff[siz]; // I voluntarily omitted dynamic allocation.
memcpy(buff,a,siz);
memcpy(a,b,siz);
memcpy(b,buff,siz);
}
In C, this approach is usually okay (and it's used by standard functions such as qsort()). The contra-indications that indicate you can't use this are when there are any pointers to your objects or their members. Also, take care in multi-threaded code.
Note that in C++, we have std::swap() which will respect user-defined copy/move constructors; copying a C++ object by simply copying its memory is not (in general) valid.
This swap() function is as good/bad as the memcpy() it uses.
If the data structures are just some data structures (of int, float, etc.), it works like a charm.
If you pass two pointers to different structures, all hell will break loose. Offending code:
Foo* myFoo = ...;
Bar* myBar = ...;
swap(myFoo, myBar, sizeof(*myFoo));
Note that your compiler won't complain on this as both pointer types are implicitly convertible to the void*s that swap() expects. But the result of compilation will be bullshit.
If the structure you copy contains a pointer into itself, that pointer will point into the other object after the swap(). The following struct would be an offender of this:
typedef struct {
char* data;
size_t length, allocatedLength;
char shortStringBuffer[32];
} myString;
The idea behind this is, that short strings will be stored in the shortStringBuffer, and data will point to the shortStringBuffer. Strings longer than 31 characters will be stored in dynamically allocated memory, and again be accessible via the data member. It is left as an exercise to the reader to figure out, what precisely happens when you try to copy this thing with a memcpy().
What you must understand, is that memcpy() really only copies bytes, and some data is not invariant to where it is stored. So, each and every use of memcpy() must be accompanied with a proof that it does the correct thing in this particular case. Well, it should. I've never seen such a proof in a comment for some reason...
You can just swap their addresses without further operation to swap two variables/arrays. I tried this and it works:
#include <stdio.h>
int main(void) {
char *a = "home";
char *b = "root";
char *c = a, *d = b;
printf("%s %s\n", a, b);
a = d;
b = c;
printf("%s %s \n", a, b);
return 0;
}
Outputs:
home root
root home
https://ideone.com/MMCOpf
It is safe to use generic pointers to swap, however you must make sure you get the sizes right, and that you don't overflow any array or object:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int swap(void *a, void *b,
size_t a_size, size_t b_size);
int main(void) {
char a[] = "home";
char b[] = "door";
printf("%s %s\n", a, b);
int ret = swap(a, b, sizeof(a), sizeof(b));
if(ret) {
printf("%s %s \n", a, b);
}
return ret;
}
int swap(void *a, void *b,
size_t a_size, size_t b_size)
{
if (b_size != a_size ) {
return 0;
}
void *tmp = malloc(a_size);
if(!tmp) {
return 0;
}
memcpy(tmp, a, a_size);
memcpy(a, b, b_size);
memcpy(b, tmp, a_size);
free(tmp); // tmp no longer needed.
return 1;
}
I solved this by C, code for your reference.
Using uint16_t is neccessary to hold the carry bit when two large uint8_t variables plus.
int main(){
uint8_t tmp[9] = {0x0};
for (int i=9-1; i>=0 ; i--) *(tmp+i) = 0xff-i;
uint16_t tmp2[9];
for (int i=0; i<9; i++) tmp2[i] = tmp[i];
byte_swap_uint8_data(tmp2, 9);
}
void byte_swap_uint8_data(uint16_t* data, int w) {
if (w < 2) return;
for (int i=0; i<w/2; i++) {
data[i] += data[w-1-i];
data[w-1-i] = data[i] - data[w-1-i];
data[i] = data[i] - data[w-1-i];
}
}

Strcmp causes segfault

Here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int my_compare(const void * a, const void * b);
int main()
{
char s[][80] =
{ "gxydyv", "gdyvjv", "lfdtvr", "ayfdbk", "sqkpge", "axkoev", "wdjitd", "pyrefu", "mdafyu",
"zdgjjf", "awhlff", "dqupga", "qoprcn", "axjyfb", "hfrgjf", "dvhhhr" };
int i;
puts("#Before:#");
for (i = 0; i < 16; i++)
puts(s[i]);
qsort(s, 16, sizeof *s, my_compare);
putchar('\n');
puts("#After:#");
for (i = 0; i < 16; i++)
puts(s[i]);
return 0;
}
int my_compare(const void *a, const void *b)
{
return strcmp(*(char **)a, *(char **)b);
}
Here is the output:
#Before:#
gxydyv
gdyvjv
lfdtvr
ayfdbk
sqkpge
axkoev
wdjitd
pyrefu
mdafyu
zdgjjf
awhlff
dqupga
qoprcn
axjyfb
hfrgjf
dvhhhr
Segmentation fault
I also notice that the prototype of strcmp is:
int strcmp(const char *s1,const char *s2);
I suppose that the type of a and b in my_compare is "pointer to array-of-char". As a result, *(char **)a is a "pointer to char", which is exactly what strcmp expects.
So where is the problem?
Change:
return strcmp(*(char **) a, *(char **) b);
To:
return strcmp(a,b);
You had an extra level of pointer dereferencing that was incorrect and that's why you got the segfault. That is, you were passing the char values and not the char pointers [which got masked with the cast].
Note: no need to cast from void * here.
UPDATE:
In reponse to your question, yes, because of the way you defined s and the qsort call.
Your original my_compare would have been fine if you had done:
char *s[] = { ... };
And changed your qsort call to:
qsort(s, 16, sizeof(char *), my_compare);
To summarize, here are two ways to do it
int
main()
{
char s[][80] = { ... }
qsort(s, 16, 80, my_compare);
return 0;
}
int
my_compare(const void *a, const void *b)
{
return strcmp(a,b);
}
This is a bit cleaner [uses less space in array]:
int
main()
{
char *s[] = { ... }
qsort(s, 16, sizeof(char *), my_compare);
return 0;
}
int
my_compare(const void *a, const void *b)
{
return strcmp(*(char **) a,*(char **) b);
}
UPDATE #2:
To answer your second question: No
None of these even compile:
return strcmp((char ()[80])a,(char ()[80])b);
return strcmp(*(char ()[80])a,*(char ()[80])b);
return strcmp((char [][80])a,(char [][80])b);
return strcmp(*(char [][80])a,*(char [][80])b);
But, even if the did, they would be logically incorrect. The following does not compile either, but is logically closer to what qsort is passing:
return strcmp((char [80])a,(char [80])b);
But, when a function passes something defined as char x[80] it's just the same as char *x, so qsort is passing char * [disguised as void *].
A side note: Using char *s[] is far superior. It allows for arbitrary length strings. The other form char s[][80] will actually fail if a given string exceeds [or is exactly] 80 chars.
I think it's important for you to understand:
Arrays are call by reference.
The interchangeability of arrays and pointers.
The following two are equivalent:
char *
strary(char p[])
{
for (; *p != 0; ++p);
return p;
}
char *
strptr(char *p)
{
for (; *p != 0; ++p);
return p;
}
Consider the following [outer] definitions:
char x[] = { ... };
char *x = ...;
Either of these two may be passed to strary and/or strptr in any of the following forms [total of 20]:
strXXX(x);
strXXX(x + 0);
strXXX(&x[0]);
strXXX(x + 1);
strXXX(&x[1]);
Also, see my recent answer here: Issue implementing dynamic array of structures
You can just cast it to a const char *, it should work now:
int my_compare(const void *a, const void *b) {
return strcmp((const char *)a, (const char *)b);
}
And also you should add:
#include <stdlib.h>

Why this qsort() doesn't work?

Am sorting an array of strings (case insensitive).
qsort causes segmentation fault, probably my casting isn't proper.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare(const void *string1, const void *string2) {
char *a = (char*)(string1);
char *b = (char*)(string2);
printf("comparing %s AND %s\n", a, b);
return strcasecmp(a,b);
}
void sortListName(char **fileList, int noOfFiles) {
printf("Sorting\n");
qsort(fileList, noOfFiles, 260*sizeof(char), compare);
return;
}
**fileList = array of strings (filenames)
P.S. main() is obvious and works fine.
If this is all the code you have related to the qsort, it looks like you declared the comparePtr function pointer, but it's still not initialized; it's not pointing to your compare function (which is what I assume you wanted it to point to).
After that, a few more things:
1) comparePtr has the correct types, but compare does not. It needs to take in two const void*, but you have two const void**.
2) Once you fix the types, you could just pass compare to qsort, instead of making a function pointer and passing that.
3) I'm not convinced the first argument to qsort is correct. You want to be passing in the pointer to the first element in the array, which ought to just be fileList (I'm assuming it points to the first string in your array).
4) The third argument isn't correct either. fileList is a char**, meaning you're passing in an array of char *s, and hence the third argument should just be sizeof(char*), not the strlens of the strings.
I would adjust things so that you're just sorting a simple array, in this case of pointers to char - qsort will arrange for you to get pointers to two elements in that array (that is, char ** pointers), and some basic dereferencing is needed to get you to the "pointers to char" comparable via strcasecmp. #Mark likely has sussed out the source of the 260 in your unseen calling code, but I'm not a big fan of those kinds of 2d arrays in C.
The following functions for me, with an example main() to exercise it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare(const void *v1, const void *v2){
char *a = *(char **)v1;
char *b = *(char **)v2;
printf("comparing %s to %s\n", a, b);
return strcasecmp(a,b);
}
void sortListName(char **fileList, int noOfFiles){
printf("Sorting\n");
qsort(fileList, noOfFiles, sizeof(*fileList), compare);
return;
}
int
main(void)
{
char *filenames[] = {
"/var/www/icons/comp.gray.png",
"/var/www/error/HTTP_SERVICE_UNAVAILABLE.html.var",
"/var/www/icons/right.gif",
"/var/www/error/HTTP_NOT_IMPLEMENTED.html.var",
"/var/www/icons/pie3.png",
"/var/www/icons/pie2.png",
"/var/www/htdocs/manual/mod/mod_proxy_balancer.html",
"/var/www/htdocs/manual/programs/rotatelogs.html",
"/var/www/htdocs/manual/vhosts/mass.html",
"/var/www/icons/movie.png",
"/var/www/htdocs/manual/images/caching_fig1.png",
"/var/www/htdocs/htdig/search.html",
"/var/www/icons/generic.gif",
"/var/www/htdocs/manual/mod/quickreference.html",
"/var/www/icons/small/blank.png",
"/var/www/icons/image2.gif"
};
int i, nf = (int) (sizeof(filenames) / sizeof(filenames[0]));
puts("Unsorted:");
for (i = 0; i < nf; i++) {
puts(filenames[i]);
}
sortListName(filenames, nf);
puts("Sorted:");
for (i = 0; i < nf; i++) {
puts(filenames[i]);
}
return 0;
}

How to print reversal of a string without using inbuilt functions and loops in C?

I have come across this question in a programming contest, but couldn't find the answer can anyone please help me with this???
Input<<string
Output<<reverse(string)
constraints: No loops allowed,No inbuilt functions have to be used!
Use recursion:
#include <stdio.h>
void print_reversed(const char* str) {
if (*str) {
print_reversed(str + 1);
printf("%c", *str);
}
}
int main() {
print_reversed("abcdef");
printf("\n");
}
To give a concrete answer based on NPE's hint to use recursion, we need to use recursion for two things: finding the end of the string, and actually swapping everything.
Here is a complete program illustrating this approach (see it run):
#include <stdio.h>
char * find_end_of_string(char *str)
{
return *str ? find_end_of_string(str + 1) : str;
}
void do_reverse_string(char *a, char *b)
{
char tmp;
if (a < b) {
tmp = *a;
*a = *b;
*b = tmp;
do_reverse_string(a + 1, b - 1);
}
}
void reverse_string(char *str)
{
do_reverse_string(str, find_end_of_string(str) - 1);
}
int main() {
char odd[] = "abcde";
char even[] = "abcdef";
reverse_string(odd);
reverse_string(even);
printf("%s\n%s\n", odd, even);
return 0;
}

Resources