I have the following code:
#include <stdio.h>
void insertion_sort(char[], int);
void swap(char*, char*);
int main() {
char s[] = "hello world";
puts(s);
insertion_sort(s, sizeof(s)/sizeof(char));
puts("done\n");
puts(s);
return 0;
}
void swap(char* a, char* b) {
char tmp = *a;
*a = *b;
*b = tmp;
}
void insertion_sort(char s[], int n)
{
int i,j;
/* counters */
for (i=1; i<n; i++) {
j=i;
while ((j>0) && (s[j] < s[j-1])) {
swap(&s[j],&s[j-1]);
j = j-1;
}
printf("%s\n", s);
}
}
The problem is, after the insertion_sort() function call, s becomes empty - puts(s) prints nothing.
Please advise.
Change:
insertion_sort(s, sizeof(s)/sizeof(char));
to:
insertion_sort(s, strlen(s));
otherwise you will be including the '\0' terminator of s[] in your sort.
Note that you will need an additional header for strlen so change:
#include <stdio.h>
to:
#include <stdio.h> // printf etc
#include <string.h> // strlen etc
The problem is that the length that you pass to insertion_sort includes terminating \0 character, which happens to have value 0, so in sort it is placed as the first element of your array. This is why your last puts() prints nothing - because the first character is now "the end of a string".
I suggest you to calculate the size of a string using strlen() which will return the length of a string excluding terminating character. Or if you want to do it your way, take terminating character into consideration and substract it from the total length.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
My program need to print all the ABC but I see I have problems with the code. How I can fix it? (no pointer for this time).
What is the runtime error in the code and how to fix it?
Here is the code:
// Elvis’s hip and happening ABC-printing code
#include <stdio.h>
#include <string.h>
#define NUM_ABC_LET 26
void makeABC(char abc[NUM_ABC_LET]);
int main() {
char abcString[NUM_ABC_LET] = "";
makeABC(abcString);
puts(abcString);
return (0);
}
void makeABC(char abc[NUM_ABC_LET]) {
char letter;
for (letter = 'a'; letter <= 'z'; letter++) {
strcat(abc, letter);
}
}
The problem is that the strcat function expects both arguments to be (zero-terminated) strings. You only pass one string, and then one single character as arguments (which should give you compiler warnings).
You need to convert this single characters into a string (or an array) of a single character.
And don't forget that strings in C are zero-terminated.
What happens you use the single character as argument to the strcat function is that the compiler converts it to an int which is then in turn converted to a pointer. The problem with this is that the address 'a' (for example) is not a valid address to a string. That will lead to undefined behavior and a crash.
Your program logic is correct, the problem is the calling of the strcat() function. The strcat() function is implemented as:
char *strcat(char *dest, const char *src)
{
char *ret = dest;
while (*dest)
dest++;
while (*dest++ = *src++);
return ret;
}
The second argument must be a string instead which you pass a character.
This is the reason for your run time error.
Can you try something like following? I haven't tested the following but it should work on most part.
// Elvis’s hip and happening ABC-printing code
#include <stdio.h>
#include <string.h>
#define NUM_ABC_LET 26
void makeABC(char abc[NUM_ABC_LET]);
int main()
{
char abcString[NUM_ABC_LET + 1];
makeABC(abcString);
puts(abcString);
return 0;
}
void makeABC(char abc[NUM_ABC_LET + 1])
{
char letter;
int i=0;
for(letter = 'a'; letter <= 'z'; letter++)
{
abc[i] = letter;
i++;
}
abc[i]='\0';
}
Your program has several issues:
You cannot call strcat with a char, you must pass char * arguments, pointing to null terminated C strings.
The array into which you compose the alphabet is too short: you need to define it with a size one larger than the number of characters for the final '\0' terminator.
Here is a corrected version:
#include <stdio.h>
#include <string.h>
#define NUM_ABC_LET ('z' - 'a' + 1) // 26 ASCII letters
void makeABC(char *abc); // makeABC receives a pointer to an array of char
// this declaration is equivalent to
// void makeABC(char abc[NUM_ABC_LET+1]);
// but less error prone
int main(void) {
char abcString[NUM_ABC_LET + 1] = "";
makeABC(abcString);
puts(abcString);
return 0;
}
void makeABC(char *abc) {
char letter;
char buf[2]; // a buffer for a 1 letter C string
for (letter = 'a'; letter <= 'z'; letter++) {
buf[0] = letter; // make a 1 letter string
buf[1] = '\0'; // set the null terminator
strcat(abc, buf);
}
}
Prototype of strcat is
char *strcat(char *destination, const char *source);
means our source as well as destinations should and must be string so this is the issue that why if you compile in turbo c it will through error of
"type mismatch".
and if you wanna write program for printing ABC up to Z than simply write
void main()
{
int i;
for(i = 65; i<=90; i++)
{
printf("%c", i);
}
}
I hope you will like it......
As a slight variation, I would suggest passing the length of the character array to the function, so that the function does not overflow the array.
As the character array is passed to the function as a pointer, the function does not know it's size.
In your case you know the size, but for the future it might be better to explicitly pass the size.
Also I just copied the characters rather than use strcat, and added the null termination at the end.
#include <stdio.h>
#define NUM_ABC_LET 26
/* function takes pointer to array and size of array */
void makeABC(char *abc, int len);
int main()
{
/* array needs to include space for null termination */
char abcString[NUM_ABC_LET + 1];
/* call function with pointer + size */
makeABC(abcString, NUM_ABC_LET);
printf("%s\n", abcString);
return (0);
}
void makeABC(char *abc, int len)
{
int n;
for(n = 0; n < len; n++ ) {
/* add letters to the array */
abc[n] = n + 'a';
}
/* put a null termination on the end */
abc[n] = '\0';
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int reverse(char *, int);
main()
{
char *word = "Thanks for your help";
reverse(word, strlen(word));
printf("%s", word);
getchar();
}
int reverse(char *line, int len)
{
int i, j;
char *newline = malloc(strlen(line));
for (i = len - 1, j = 0 ; i >= 0; i--, j++)
{
newline[j] = line[i];
}
newline[j] = '\0';
line = &newline;
}
Hey folks. I've got a simple C question that I can't seem to solve.
The program above is meant to take in a string and print it out backwards. Reverse is the function by which this is done.
The issue, specifically, is that when I print word in main(), the string appears unchanged. I've attempted to make the address of line the address of newline, but it doesn't have any effect.
int reverse(char *line, int len)
{
int i, j;
char *newline = malloc(strlen(line));
for (i = len - 1, j = 0 ; i >= 0; i--, j++)
{
newline[j] = line[i];
}
newline[j] = '\0';
line = &newline; // Your problem is here
}
You're merely assigning to the local line pointer. This has no effect on the calling function whatsoever.
Consider instead:
char *reverse(char *line, int len)
{
// ...
return newline;
}
Additional advice:
Turn on compiler warnings, and heed them. You've got lots of little things wrong (e.g. reverse isn't currently returning anything, but is declared as returning int).
Given that the first argument of reverse is a pointer to a C string (NUL-terminated), there's no need to take a length argument as well.
A reverse function doesn't necessarily need to be defined as returning a copy of the string, reversed. It could instead reverse a string in-place. Note that you cannot pass a string literal to a function like this, as they are read-only.
Here's how I would write this:
#include <stdio.h>
#include <string.h>
void reverse(char *str)
{
size_t i, j;
for (i = strlen(str) - 1, j = 0 ; i > j; i--, j++)
{
// Swap characters
char c = str[i];
str[i] = str[j];
str[j] = c;
}
}
int main(void)
{
// Mutable string allocated on the stack;
// we cannot just pass a string literal to reverse().
char str[] = "Here is a test string";
reverse(str);
printf("Result: \"%s\"\n", str);
return 0;
}
Note that the for loop condition is i > j, because we want each to only traverse half the array, and not swap each character twice.
Result:
$ ./a.exe
Result: "gnirts tset a si ereH"
Take a look at the code below:
void addOne(int a) {
int newA = a + 1;
a = newA;
}
int main() {
int num = 5;
addOne(num);
printf("%d\n", num);
}
Do you see why that will print 5, and not 6? It's because when you pass num to addOne, you actually make a copy of num. When addOne changes a to newA, it is changing the copy (called a), not the original variable, num. C has pass-by-value semantics.
Your code suffers from the same problem (and a couple other things). When you call reverse, a copy of word is made (not a copy of the string, but a copy of the character pointer, which points to the string). When you change line to point to your new string, newLine, you are not actually changing the passed-in pointer; you are changing the copy of the pointer.
So, how should you implement reverse? It depends: there are a couple options.
reverse could return a newly allocated string containing the original string, reversed. In this case, your function signature would be char *reverse, instead of int reverse.
reverse could modify the original string in place. That is, you never allocate a new string, and simply move the characters of the original string around. This works, in general, but not in your case because char pointers initialized with string literals do not necessarily point to writable memory.
reverse could actually change the passed-in pointer to point at a new string (what you are trying to do in your current code). To do this, you'd have to write a function void reverse(char **pointerToString). Then you could assign *pointerToString = newLine;. But this is not great practice. The original passed-in argument is now inaccessible, and if it was malloc'd, it can't be freed.
I need to write a probram in C, which adds a string to a string etc. (for example '5' strings - It needs to read "vbvbvbvbvb" 5 times.) But it doesn't work? Help please!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char s[80];
int len;
int counter = 0;
char* repeat(char* s, int n) {
if (n > 0) {
if (s[len] == n) {
counter++;
}
len--;
repeat(s, (n++));
}
return s;
}
int main(void) {
printf("%s", repeat("vb", 5));
fflush(stdout);
return EXIT_SUCCESS;
}
You're trying to write into the end of "vb" which is a string in the constant pool. Don't do that. Allocate a string that is strlen(s) * n + 1 long and write into that.
Your base case is probably wrong. The base case should probably be when n == 0 which is when the empty string (nothing appended except terminating NUL as below) is appropriate.
Your recursive step (n++) should probably be (n - 1) to count down to that base case. As written, the post-increment does a useless assign and recurses with the same value of n.
I don't know what counter and len are supposed to do, but they looks redundant to me. len is uninitialized, so s[len] has undefined behavior.
After writing the n copies, you need to add a terminating NUL ('\0') at the end so that printf and similar functions can identify the end.
You are using s both as a global and a local variable, the function is working on the local.
Try not to use global variables where not necessary. Also, recursion is not necessary for this.
#include <stdio.h>
void concatenate_string(char *dest, const char *src, int n) {
char *s;
while(n--) {
s = (char*)src;
while(*(s))
*(dest++)=*(s++);
}
*(dest++) = 0;
}
int main(void) {
char out[80];
concatenate_string(out, "ab", 5);
printf("%s", out);
return 0;
}
I am trying to write a function, uppercase, that converts all lowercase characters in a string into their uppercase equivalents.
However, I am getting a Bus 10 error in my code. I know that string literals cannot be modified in C; so, I am not sure if this is the right approach.
My code is below:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
int uppercase(char source[])
{
int i;
for(i=0; i<=strlen(source); ++i)
if (source[i]>= 'a' && source[i]<= 'z')
source[i]= source[i]-'a' +'A';
else
source[i]=source[i];
}
int main(){
uppercase("cold");
return 0;
}
Ideally this function should return COLD.I suppose the error lies in my whole if statement.
The reason you get a crash is that your code modifies a string literal. Characters inside string literals are placed in protected memory area, and therefore may not be changed: it us undefined behavior.
Replace this
uppercase("cold");
with this:
char cold[] = "cold";
uppercase(cold);
Now the characters of the string are placed in a modifiable area of memory, allowing you to make changes as needed.
Your absolutly working with pointers without even to know it.
In your function definition
int uppercase(char source[])
char source[] is considered by the compiler as a pointer to char (char *source)
So when passing a string literal to uppercase() your just passing it's adress. Then in your function your trying to modify it which leads to undefined behaviour.
Also you can't return a whole array so you just return a pointer to it.
char *uppercase(char source[])
{
int i;
size_t len = strlen(source);
char *tmp;
tmp = malloc(len+1);
if (tmp!=NULL){
memcpy(tmp, source, len+1);
for(i=0; i<len; ++i){
if (tmp[i]>= 'a' && tmp[i]<= 'z'){
tmp[i]= tmp[i]-'a' +'A';
}
}
}
return tmp;
}
Then:
int main(){
char *str = uppercase("cold");
printf("%s", str);
free(str);
return 0;
}
You complete code: http://ideone.com/BJHDIF
I see a very interesting code to reverse a string,
but I don't understand here:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void Reverse(char *s);
int main()
{
char *s=NULL;
s=(char *)malloc(sizeof(char *));
gets(s);
Reverse(s);
puts(s);
return 0;
}
void Reverse(char *s)
{
char *end=s;
char tmp;
if (s)
{
while (*end)
{
++end;
}
--end;
while (s<end) ??
{
tmp=*s;
*s++=*end;
*end--=tmp;
}
}
}
I see the this program tries to work on the same string by using end=s to change both string at the same time, but what does '*' line : while(s<end) here mean?
I use gdb and find that when we input asdfgh, when *s is fdsa and *end is fds, this is no longer true, how this line controls the program?
I just want to know what '??' line mean..
Thanks a lot !
Strings in C are terminated by the \0 character, which has the integer value 0. As such it is a false value.
By using while(*end) you check whether end is pointing on the termination character of the given string. If it isn't pointing on the end, you move it further (++end). To ensure that the pointer is valid you move the "cursor" backward after this.
while(s < end) will now move check whether s is further forwarded than end. If not, then you'll swap the value of both "cursor". end will move toward s and vice versa. This way you're going to reverse the string.
You're debugging output is a result of gdbs interpretation. It interpreds end as a string, not a single character. Have a look at *end while debugging.
Note that your malloc is completely wrong. You have to allocate enough memory for the string, for example s = malloc(500*sizeof(char));. Use fgets instead, where you can specify the maximum number of characters to be read. Don't forget to free all memory you allocate:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 500
void Reverse(char *s);
int main()
{
char* s = malloc(BUFFER_SIZE * sizeof(char));
fgets(s,BUFFER_SIZE,stdin);
Reverse(s);
puts(s);
free(s);
return 0;
}
void Reverse(char *s)
{
char* end=s;
char tmp;
if(s)
{
while (*end)
{
++end;
}
--end;
while (s<end)
{
tmp=*s;
*s++=*end;
*end--=tmp;
}
}
}
s and end are char pointer so the test (s < end) is true until the s pointer doesn't become greater than then end pointer.
Example
Assume that you want to reverse the string "hello" stored at the address 0x0000, ad the start of the function you have:
s = 0x0000
end = 0x003
now the while loop:
s=0x0000 e=0x0003 *s=o *e=h
s=0x0001 e=0x0002 *s=l *e=e
s=0x0002 e=0x0003 << while exit >>