strShiftLeft(char* str, int n) keeps getting "zsh: bus error" - c

I'm trying to implement a C function char* strShiftLeft(char* str, int n) that takes in a string (str) and an int n, which represents how many chars to shift str to the left. For example, if we call it as strShiftLeft("Thomas", 2), the function should return a char pointer pointing to a string "omasTh" as we append the first 2 (n) chars to the end of string and shift every char 2 slots to the left.
However, for some reason, when I compile my program, it compiles fine but when I run it on my mac, my terminal keeps showing me:
zsh: bus error ./a.out
Here's my code:
#include <stdio.h>
#include <stdlib.h>
char* strShiftLeft(char* str, int n)
{
// If the passed in string is NULL, return NULL
if (str == NULL)
{
printf("NULL!\n");
return NULL;
}
// Get the length of the string
int len = 0;
char* counter_ptr = str;
while (*counter_ptr != '\0')
{
len++;
counter_ptr++;
}
printf("len: %d\n", len);
// If the integer is longer than the string, return back NULL
if (n > len)
{
printf("n too big!\n");
return NULL;
}
// Create a temp char array to store 1st n chars to append to the end of string later
char temp_arr[n];
for (int i = 0; i < n; i++)
{
*(temp_arr + i) = *(str + i);
}
printf("temp_arr = %s\n", temp_arr);
printf("str is still: %s\n", str);
// So far so good
char* temp = str + n;
printf("len - n = %d\n", len - n);
// Update first (len - n) characters of the string (e.g. n = 2, "Thomas" -> "omasas")
for (int i = 0; i < (len - n); i++)
{
printf("*temp = %c\n", *temp);
printf("*(temp - n) = %c\n", *(temp - n));
*(temp - n) = *(temp); // THIS LINE SEEMS TO BE THE ONE CAUSING ERRORS
temp++;
}
temp = str + (len - n);
for (int i = 0; i < n; i++)
{
*(temp + i) = *(temp_arr+i); // THIS LINE ALSO SEEMS TO BE CAUSING ERRORS
}
return str;
}
int main()
{
char* str = strShiftLeft("Thomas", 2);
printf("%s\n", str); // Should print out "omasTh"
return 0;
}
I used a lot of printf()s to try to find out what went wrong. I noticed two particular lines of code seem to be causing some errors, namely:
1)
*(temp - n) = *(temp);
*(temp + i) = *(temp_arr+i);
What I'm trying to do with these 2 lines of code is that I want to update the values of certain elements in the string with values from other elements in the string.
Although my code compiles, when I run it, it shows "zsh: bus error ./a.out". I tried using some online compiler. When I ran my code, I got seg fault.
I don't know what mistakes I've made.
Would be much appreciated if someone can help me identify the mistakes I've made.
Note that, I'm not allowed to use dynamic memory allocation, bracket operator for dereferencing pointers, or any functions from the C library such as strlen(), strcpy() etc. Thanks!
I've used printf() to pinpoint which lines are causing errors, but I don't understand why they're causing errors.

When you invoke strShiftLeft("Thomas", 2); you are passing strShiftLeft() the address of a string literal.
strShiftLeft() then proceeds to try and modify in-place the string that you passed to it, which means that it tries to modify a string literal.
Modifying a string literal in C is "undefined behavior", which means that anything may happen.
Anything includes:
Nothing. This will happen if you are running in some environment which happens to be storing C string literals in read-write memory. (And is treacherous, because it might give you the impression that your program works, while it doesn't.)
Bowls of petunias and sperm whales fall from the sky. (Mandatory HGGTG reference.)
More likely: Your program gets terminated due to a segmentation fault (segfault) because the string literal was stored in read-only memory and your program attempted to write to that memory.
However, this is not what is happening in your case, because you are not receiving a segfault, you are receiving a bus error. A bus error means that your program did not just attempt to write to read-only memory; it means that it attempted to address memory which cannot even be addressed.
What is causing your bus error is most probably the following:
printf("temp_arr = %s\n", temp_arr);
What happens is that you forgot to null-terminate your temp_arr, so the printf() function prints whatever temp_arr contains and then continues printing after the end of temp_arr. Since temp_arr is in the stack, printf() attempts to read from memory past the end of the stack, which is in all likelihood some invalid page.
This is one more reason to start using a debugger and stop using printf() statements.

Related

For loop is running too often

I have a for loop which should run 4 times but is running 6 times.
Could you please explain the behaviour?
This is strange because stringarr1 is not changed.
Edit: I want to remove all '!' from my first string and want to save the letters in a second string.
#include <stdio.h>
#include <math.h>
#include <string.h>
int main(){
char stringarr1[] = "a!bc";
char stringarr2[] = "";
printf("%d\n", strlen(stringarr1)); // lenght --> 4
for (size_t i = 0; i < strlen(stringarr1); i++)
{
printf("i: %d\n", i);
if (stringarr1[i] != '!') {
stringarr2[strlen(stringarr2)] = stringarr1[i];
printf("info: != '!'\n");
}
}
}
You are overrunning the buffer for stringarr2 (length 1), which is in this case corrupting the memory-adjacent stringarr1, causing the string length to change by overwriting its nul terminator.
Then because you are reevaluating the string length on each iteration, the loop will run for a non-deterministic number of iterations - in your case just 6, but it could be worse; the behaviour you have observed is just one of several possibilities - it is undefined.
Apart from correcting the buffer length for stringarr2, it is best practice to evaluate loop-invariants once (although in this case the string length is not invariant due to a bug). So the following:
const size_t length = strlen( stringarr1 ) ;
for( size_t i = 0; i < length; i++ )
{
...
will run for 4 iterations regardless of the buffer overrun bug because the length is not reevaluated following the corruption. Re-evaluating loop-invariants can lead to very slow code execution.
Your code can run any number of times. You write beyond the end of stringarr2 so you may be smashing the stack and overwriting local variables. What you meant to do is probably something like this:
#include <stdio.h>
#include <math.h>
#include <string.h>
int main(){
char stringarr1[] = "a!bc";
char stringarr2[10];
int len = strlen(stringarr1);
printf("%d\n", len); // lenght --> 4
for (size_t i = 0; i < len; i++)
{
printf("i: %d\n", i);
if (stringarr1[i] != '!') {
stringarr2[len] = stringarr1[i];
printf("info: != '!'\n");
}
}
}
Like others said, it is not really clear what you are trying to accomplish here. But in C, a declaration like char s[] = "string" only allocates enough memory to store whatever is on the right hand side of the assignment. If that is an empty string like in your case, only a single byte is allocated, to store the end of string 'null' character. You need to either explicitly specify, like I did, the number of bytes to allocate as the array size, or use dynamic memory allocation.
The problem is that you're writing past the end of stringarr2. This triggers undefined behaviour.
To fix this, you need to allocate sufficient memory for stringarr2.
First, we must allocate the string to be long enough.
char stringarr1[] = "a!bc";
//save this in a variable beforehand because strlen loops over the string every time it is called
size_t len = strlen(stringarr1);
char stringarr2[1024] = { 0 };
{ 0 } initializes all characters in the string to 0, which means the last one will always be a null terminator after we add characters. This tells C string functions where the string ends.
Now we can put stuff in there. It seems like you're trying to append, so keep a separate iterator for the 2nd string. This is more efficient than calling strlen every loop.
for(size_t i = 0, j = 0; i < len; i++){
printf("i: %d\n", i);
if (stringarr1[i] != '!') {
stringarr2[j++] = stringarr1[i];
printf("info: != '!'\n");
}
}

C - Replace substring in string

As a part in my process to learn C I am developing a couple of functions for string manipulations. One of these has the function of replacing substrings within a string, and is raising some questions. I am working in C99; compiling on Mac OS Sierra and FreeBSD.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *repstr(char input[], char rep[], char new[]) {
char *output = malloc(strlen(input)*5); // <- Question 2
int replen = strlen(rep);
int newlen = strlen(new);
int a, b, c = 0;
// printf("input: %ld\t%s\n", strlen(input), input); // <- Question 1
while(input[a]) {
if(input[(a+b)] == rep[b]) {
if(b == replen - 1) {
strcat(output, new);
a += replen;
c += newlen;
b=0;
}
else b++;
} else {
output[c] = input[a];
a++;
c++;
}
}
return output;
}
int main() {
char buffer[] = "This is the test string test string test test string!";
char rep[] = "test";
char new[] = "tested";
int len = strlen(buffer);
char output[len+5];
printf("input: %d\t%s\n", len, buffer); // <- Question 1
strcpy(output, repstr(buffer, rep, new));
printf("output: %ld\t%s\n", strlen(output), output);
return 0;
}
Question 1: When this line is executed in main() it causes a segfault. However, when executed within the function everything seems to work fine. Why?
Question 2: I have realized that I need a pretty large piece of memory allocated for the output to look as expected. strlen(input)*5 is an arbitrary number which seems to work, but why do I get seemingly 'random' errors when lowering the number?
NB! As this is a part of my process to learn coding in C I am not primarily interested in (more efficient) pre-fab solutions for solving the problem (already have them), but to explain the two questions listed - so that I can solve the problem myself.
Also; this is my first post in the SO forums. Hello.
Question 1: When this line is executed in main() it causes a segfault.
However, when executed within the function everything seems to work
fine. Why?
No, printf("input: %d\t%s\n", len, buffer); // <- Question 1 is not the cause of your segfault.
printf("output: %ld\t%s\n", strlen(output), output);
This part is, strlen doesn't return int but it returns size_t. As noted in the comments, use %zu to print it out.
Also, while(input[a]) will stop at the NULL terminator which means that your output will never hold a terminator and thus printf will keep on reading, you should add it at the end:
output[c] = '\0';
Also, as noted by #LPs in the comments, you should zero initialize the variables you work with :
int a = 0, b = 0, c = 0;
Question 2: I have realized that I need a pretty large piece of memory
allocated for the output to look as expected. strlen(input)*5 is an
arbitrary number which seems to work, but why do I get seemingly
'random' errors when lowering the number?
Probably because you haven't allocated enough memory. Because the string length depends on runtime factors there's no way to know the exact memory needed you should allocate the maximum amount required:
char *output = malloc(strlen(input) * strlen(new) + 1);

Unexpected output after the first iteration of this code [closed]

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 7 years ago.
Improve this question
I honestly have no idea how the following even happens. Here is the code:
while(1)
{
char** line = read_command();
char* command = line[0];
char** parameters = malloc(100);
int i;
for(i = 0; i < pNum; i++) // pNum is a global var containing the number of words read from read_command()
{
parameters[i] = line[i];
printf("%i: %s", i, parameters[i]);
}
printf("%s\n", parameters[0]);
parameters[0] = "/usr/bin/";
strcat(parameters[0], command);
printf("%s\n", command);
printf("%s\n", parameters[0]);
if(fork() != 0)
waitpid(1, &status, 0);
else
execve(parameters[0], parameters, NULL);
}
read_command() returns a char** that is basically an "array" to the string that was entered, and each char* contains a word. Like if I enter "hello people of earth" the result would be ["hello", "people", "of", "earth"]. This fucntion always works.
upon the first iteration everything works just as expected. example, when I type "date" the output is as follows:
0: date
date
date
/usr/bin/date
and then the date is displayed
but upon the second iteration if i use "date" as the input again the output is as follows:
0:date
edate
/usr/bin/datedate
and the date command is not issued
the second printf statement always prints "e" after the first iteration even if I print a constant string like "hello". and then the parameters[0] somehow has 2 "date" in it even though the command pointer has only 1 "date".
And after the third iteration the program does not wait for user input, it just loops non stop and displays "PM: warning, process table is full!"
What could possibly cause this?
I am working in MINIX 3.1.0 with the cc compiler for C
EDIT:
the read_command():
char* line = malloc(), * linep = line;
size_t lenmax = 100, len = lenmax;
int c;
int currPos = 0;
int currParam = 0;
int i;
char** parameters = malloc(100);
if(line == NULL)
return NULL;
while(1)
{
c = fgetc(stdin);
if(c == EOF) || c == '\n')
break;
if(--len == 0)
{
char* linen = realloc(linep, lenmax *= 2);
len = lenmax;
if(linen == NULL)
{
free(linep);
return NULL;
}
line = linen + (line - linep);
linep = linen;
}
if((*line++ = c) == '\n')
break;
}
*line = '\0'; // everything up to this point i got from this link: http://stackoverflow.com/a/314422/509914
parameters[currentParam] = malloc(100);
for(i = 0; i < strlen(linep); i++);
{
if(isspace(linep[i]) || line[i] == EOF)
{
parameters[currParam][currPos] = '\0;
currPos = 0;
parameters[++currParam] = malloc(100);
}
else
parameters[currParam][currPos++] = line[i];
}
parameters[currParam][currPos] = '\0';
pNum = currParam + 1;
return parameters;
It sure is interesting that those people who learn by reading reputable resources, such as the tried and tested for decades K&R tend to have these issues far less frequently than those who don't...
char** parameters = malloc(100); is attempting to allocate 100 bytes. realloc behaves similarly, so I won't mention this again. Perhaps you meant to allocate 100 lots of char *? It'd make even more sense to allocate pNum lots of char *: char **parameters = malloc(pNum * sizeof *parameters);... char* linen = realloc(linep, (lenmax *= 2) * sizeof *linep);...
strcat doesn't allocate memory; the only functions that allocate memory are malloc, calloc and realloc.
When you call strcat(foo, bar); you're asking strcat to append the string pointed to by bar onto the end of the string pointed to by foo. In your code, you're attempting to modify a string literal. Undefined behaviour, and typically a segfault.
Even your modified attempt is wrong. In parameters[0] = "/usr/bin/";, you're not copying a string into parameters[0]; you're assigning parameters[0] to point to the string (which is typically in immutable memory, as I mentioned earlier). You really need to narrow down the source of your undefined behaviour by creating an MCVE...
In the first line of your read_command() function, char* line = malloc(), * linep = line;, you have called malloc without providing an argument. That's a constraint violation. Your compiler should be issuing you with an error. Perhaps you've forgotten to #include <stdlib.h>, and so malloc is missing its prototype? Please provide an MCVE so we don't have to make guesses like this.
There's another constraint violation at if(c == EOF) || c == '\n')... Even if we were to fill in the blanks to produce an MCVE for you (which we shouldn't have to do, because it's your work and you're asking us for help), this code would not compile. Perhaps that's what's causing your crashes? Always check the messages that your compiler gives you. Don't ignore warnings... and definitely don't ignore error messages.
I compared the code that you claimed came from this answer, and it is quite different. The code at that answer compiles, for one. Nonetheless, is that your way to establish trust with the people who are trying to help you... by lying?
You don't need so much dynamic allocation, and normally I would go out of my way and explain how you can do this the best way possible, but the lies have put me off. I have one more point to make: Make sure parameters is terminated by a null pointer (similarly to how strings are terminated by a null character), as it is required to be by the manual.

Dynamic 2D array crashes

I am reading from a file (each line wolds 1 word) and putting each line into an array. It crashes when its about to close the file saying (* glibc detected * proj: corrupted double-linked list: 0x0000000002139240 ***). Also everything but the 1st element was copied correctly (the 1st element was supposed to be "how are you" but was instead "0"). Any help on this is greatly appreciated.
int i = -1;
int numb;
int wsize;
while (fgets(word,30,file)!=NULL)
{
if (i==-1)
{
if(word[strlen(word)-1]=='\n')
{
word[strlen(word)-1] = 0;
}
numb = atoi(word);
ptr = malloc(sizeof(char*)*numb);
}
else
{
if(word[strlen(word)-1]=='\n')
{
word[strlen(word)-1] = 0;
}
wsize = strlen(word);
ptr[i] = malloc(sizeof(char*)*wsize);
strncpy(ptr[i],word,strlen(word));
size++;
}
i++;
}
int j=0;
while(j<16) //prints to see if they were copied corectly
{ //ptr[0] was the only one that did not copy corectly
printf("%s\n",ptr[j]);
j++;
}
fclose(file);
printf("test\n"); //was never printed so I assume it crashes at fclose()
return 1;
The line ptr[i] = malloc(sizeof(char*)*wsize); is wrong, for two reasons:
It should be sizeof(char), not sizeof(char*) (or just omit this, since sizeof(char) is equal to 1 by definition)
If you want to store a string of length wsize, you need to allocate wsize+1 bytes
EDIT — More issues:
What is the purpose of the line size++;? Did you mean wsize++;?
Where does the number 16 come from in while(j<16)? I suggest you try while(j<i) instead.
If main() returns a nonzero value, this signifies that an error occurred. Change this to return 0; unless you have a good reason for returning some other value.
One more:
I just noticed you're using strncpy(). This won't add a terminating '\0' byte to the end of the string because you've asked it to copy a string of length wsize using no more than wsize bytes. Change this line to strcpy(ptr[i],word); and it should work.
After you've done that, you need to remove all the potential buffer overflows from your code. (There are lots of them.)

Need help finding bug, if string input is composed all of same character one output character is corrupt

reverser() reverses a cstring (not in place). 99% of the time it works but some input corrupts it for example it appears if aStr2[] is assigned a string made up of the same character it will have an error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* reverser(const char *str);
int main()
{
char aStr[] = "aaa";
char aStr2[] = "cccccc";
printf("%s %s", aStr, aStr2);
char* tmp = reverser(aStr2);//tmp now has garbage
printf("\n%s", tmp);
printf(" %s", aStr2);
return 0;
}
char* reverser(const char *str)
{
char* revStr = (char*)malloc(strlen(str));
int i;
for(i = strlen(str)-1; i >= 0; i--)
{
revStr[strlen(str)-1-i] = str[i];
}
return revStr;
}
Gives
aaa cccccc
cccccc9 cccccc
Process returned 0 (0x0) execution time : 0.068 s
Press any key to continue
Notice the 9 that shouldn't be there.
Change this malloc to strlen(str) + 1 , plus 1 for '\0'
char* revStr = (char*)malloc(strlen(str) + 1);
and after the for loop
revStr[strlen(str)+1] = '\0';
Your problem is that you don't put the string terminator in your reversed string. All strings in C are actually one extra character that isn't reported by strlen, and that is the character '\0' (or plain and simple, a zero). This tells all C functions when the string ends.
Therefore you need to allocate space for this extra terminator character in your malloc call, and add it after the last character in the string.
There are also a couple of other problems with your code, the first is that you should not cast the return of malloc (or any other function returning void *). Another that you have a memory leak in that you do not free the memory you allocate. This last point doesn't matter in a small program like the one you have here, but will be an issue in larger and longer running programs.
You haven't null-terminated your reversed string. You need to set the final index of revStr[] to 0.

Resources