Help needed in Segmentation Error in my C code
I have been trying to identify where my program generates segmentation all to no avail. I need help in pin-pointing which of the strings operations or char pointers is causing the segmentation fault during runtime. The program compiles successfully but gives segmentation error during run-time.
#include<curses.h>
#include<strings.h>
#include<unistd.h>
#include<stdlib.h>
/*Implements a Scrolling headband that takes a string argument and continously scrolls*/
int main(int argc, char* argv[])
{
/*A Sub开发者_StackOverflow社区string function to return substring of a string*/
char *substr(const char *src, int start, int len);
/*Appends a character to the Given string*/
void append(char* s, char c);
/***Check if the argument is invalid***/
if(argc!=2)
{
puts("Invalid number of arguments: Usage:headband <String>");
}
/**Get headtext from the string argument argv[1]**/
char *headtext = argv[1];
/*headband(headtext);*/
/*temporary variable to store strings as execution progresses*/
char temp[100];
/*Counter for streaming and scolling headband text*/
int count = 0;
/*Placeholder for temporary headband text*/
char hold[100];
int i;
/*maximum x and y co-ordinates of the Screen*/
int max_x,max_y;
/*Initialize screen for ncurses*/
initscr();
/*Don't show cursor*/
curs_set(0);
/*Get terminal console dimensions*/
getmaxyx(stdscr, max_y, max_x);
/*Get console width set to default console screen width=80*/
int consolewidth = max_x;
/*Clear the screen*/
clear();
/*Set the first value as end of String for the momment*/
temp[0] = '\0';
/*Run this loop continuously to keep scrolling*/
for (;;)
{
for(i=0; i < strlen(headtext); i++)
{
count++;
/*Append headband text character by character to string hold*/
append(temp, headtext[i]);
move(0,consolewidth - count);
if (consolewidth - count > 0)
{
mvaddstr(0,console_width-count,temp);
refresh();
}
else if (consolewidth - count == 0)
{
strcpy(hold, temp);
char q;
int com = i;
for(;;)
{
/*Scroll text by triming one character at a time*/
/*from the left, then adding that character to the*/
/*right side of the text*/
com = com + 1;
if (com < strlen(headtext))
{
q = headtext[com];
}
else
{
com = 0;
q = headtext[com];
//q = hold[0];
}
strcpy(hold, substr(hold, 1, strlen(hold) - 1));
append(hold, q);
move(0,0);
clear();
mvaddstr(0,0,hold);
refresh();
usleep(50);
}
}
usleep(50);
}
}
return 0;
}
/*A Substring function to return substring of a string*/
char * substr(const char *src, int start, int len)
{
char *dest = malloc(len+1);
if (dest)
{
memcpy(dest, src+start, len);
dest[len] = '\0';
}
return dest;
}
/*Appends a character to the Given string*/
void append(char s[], char c)
{
int len = strlen(s);
s[len] = c;
s[len+1] = '\0';
}
I don't know which compiler you are using, but here is a quick guide how to debug this with GCC and GDB:
$ gcc -g file.c -o myexec # the -g flag enables debug info
$ gdb ./myexec
Now you are in the GDB prompt. If you need to set command line arguments use:
set args <arg1> <arg2> ...
Then run your program
run
Once it crashes you can do all sorts of things. It also shows at which point in the program your error happened. You probably want to use these commands:
bt # prints the backtrace / call stack
print <expr> # print value of an expression
There are a couple of cheat sheets on the web, so you can get a quick idea at what sorts of commands are available.
Use hand-debug method ;
#define DEBUG(A) fprintf(stderr, "%d step\n", (A))
#define PRINT(A) fprintf(stderr, "%s\n", (A))
#include<curses.h>
#include <strings.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc, char* argv[]){
char *substr(const char *src, int start, int len);
PRINT("at top of the main" ) ; /***/
DEBUG(1);
void append(char* s, char c);
if(argc!=2)
{
puts("Invalid number of arguments: Usage:headband <String>");
}
char *headtext = argv[1];
DEBUG (2);
char temp[100];
int count = 0;
char hold[100];
int i;
int max_x,max_y;
initscr();
DEBUG (3);
curs_set(0);
getmaxyx(stdscr, max_y, max_x);
DEBUG (4);
int consolewidth = max_x;
clear();
DEBUG(5);
temp[0] = '\0';
for (;;)
{
for(i=0; i < strlen(headtext); i++)
{
count++;
append(temp, headtext[i]);
DEBUG(6);
move(0,consolewidth - count);
DEBUG(7);
if (consolewidth - count > 0)
{
mvaddstr(0,console_width-count,temp);
refresh();
}
else if (consolewidth - count == 0)
{
char q;
int com = i;
strcpy(hold, temp);
for(;;)
{
com = com + 1;
if (com < strlen(headtext)){
q = headtext[com];
DEBUG (10);
}else{
com = 0;
q = headtext[com];
//q = hold[0];
}
strcpy(hold, substr(hold, 1, strlen(hold) - 1));
append(hold, q);
move(0,0);
clear();
mvaddstr(0,0,hold);
refresh();
usleep(50);
}
}
usleep(50);
}
}
return 0;
}
char *
substr(const char *src, int start, int len)
{
char *dest = malloc(len+1);
PRINT ( "in substr" );
if (dest)
{
memcpy(dest, src+start, len);
dest[len] = '\0';
}
PRINT ("at the end of the sub);
return dest;
}
void append(char s[], char c)
{
int len = strlen(s);
PRINT( "in append function" );
s[len] = c;
s[len+1] = '\0';
PRINT ( "at the end of the append function" );
}
compile it, then you can easily see where you take segmentation fault
The most obvious problem I see that could lead to a segmentation error is in the following code :
if(argc!=2)
{
puts("Invalid number of arguments: Usage:headband <String>");
}
char *headtext = argv[1];
After identifying that an invalid number of arguments has been provided, you proceed to assign a pointer to argv[1]
. If the user has not supplied your argument, the result is passing a NULL
to strlen()
. This results in undefined behavior and strlen(NULL)
normally crashes on Linux\Unix. In my brief testing, supplying a argument did result in a scrolling headband without any crash.
You might consider changing your code to something similar to the following:
if(argc<2)
{
puts("Invalid number of arguments: Usage:headband <String>");
exit(EXIT_FAILURE);
}
char *headtext = argv[1];
Update
It seems your current code is unnecessarily complex (e.g. nested infinite loops) for what I believe is its intended purpose. There are also a few issues with the code in its current form that should be addressed. There is a memory leak originating from the call to malloc()
in the substr()
function and subsequently losing the pointer to the allocated memory. If the user supplied text is greater than the size of your temp[100]
buffer, you will overflow the buffer in your append()
function. It is also unnecessary to compute the length of headtext
more than once as its length will not change.
I maintain that curses should be used over raw terminal escape codes. The curses library is effectively a wrapper around the raw terminal codes and provides a flexible and efficient API so that application programs do not need to worry about the underlying terminal capabilities. Perhaps the NCURSES Programming HOWTO or X/Open Curses, Reference Pages can be of some use.
I am no curses expert myself, however, the following example shows another curses-based approach that is loosely based on the original code and appears to have the same output*:
#include<curses.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
/* maximum x and y co-ordinates of the window */
int max_x, max_y;
/* pointer to headband buffer */
char * headband = NULL;
/* counter for streaming and scolling headband text */
unsigned int count;
/* Handler for window resize */
void handle_winch(int sig)
{
/* Function for initializing curses & headband buffer */
void my_init();
/* Disable signal handler during reinitialization */
signal(SIGWINCH, SIG_IGN);
/* Reinitialize the window to update data structures */
endwin();
my_init();
}
/* Function for initializing curses & headband buffer */
void my_init()
{
/* Initialize / Reinitialize screen for ncurses */
initscr();
curs_set(0);
clear();
refresh();
getmaxyx(stdscr, max_y, max_x);
/* Allocate / Reallocate and initialize scrolling headband buffer */
free(headband);
headband = (char *)malloc(max_x+1);
memset(headband, ' ', max_x);
headband[max_x] = '\0';
count = 0;
/* Setup signal handler for window resizing */
signal(SIGWINCH, handle_winch);
}
/* Implements a scrolling headband that takes a
* string argument and scrolls continously */
int main(int argc, char* argv[])
{
char * headtext;
int headtext_len;
int size;
if(argc<2)
{
puts("Invalid number of arguments: Usage:headband <String>");
exit(EXIT_FAILURE);
}
/* Get headtext from the argument argv[1] and compute length */
headtext = argv[1];
headtext_len = strlen(headtext);
/* Call common initialization / reinitialization routine */
my_init();
/* Run this loop continuously to keep scrolling */
for(;;)
{
/* Store & use copy of max_x in case original max_x is
* modified in signal handler by window resize event */
size = max_x;
/* Rotate headband by shifting entire buffer and then
* appending next character from headtext buffer */
memmove(&headband[0], &headband[1], size-1);
headband[size-1] = headtext[count++ % headtext_len];
/* Update window */
move(0,0);
mvaddstr(0,0,headband);
refresh();
usleep(50000);
}
/* Unreachable, but included for completeness */
endwin();
free(headband);
exit(EXIT_SUCCESS);
}
* Includes window resize handling
精彩评论