CS50 pset3 Music segmentation fault - c

Today I finished the music project, or at least I think I've finished it.
On helper.c when I run make it makes both notes and synthesizer files and with no errors. But when I want to run ./notes it gives me segmentation fault error. Even when I ran the program with check50 it gave me this error:
failed to execute program due to segmentation fault
I personally think it might be because of turning string to int or the way I got the notes from the string. First I introduced one string for taking the note and one int for taking the ovtav of the note.
The string note is something like D4 or C#4
So I will just copy this part, to check with you if I've done it correctly.
string noteletter="";
int noteoctav;
if (strlen(note) == 3)
{
noteletter[0] = note[0];
noteletter[1] = note[1];
noteoctav = note[2] - '0';
}
if (strlen(note)== 2)
{
noteletter[0] = note[0];
noteoctav = note[1] - '0';
}
Update
Here I've added the full code so you can see what I am trying to do.

Two problems I can see (assuming string is a typedef of char*)
if noteletter has a length of 0 (value = "") then what do you think noteletter[1] is doing?
Even if noteletter was set to something bigger (e.g. noteletter = "ABC";) - writing to a literal string is undefined behavior.
Try char noteletter[3] = { 0 }; to get something that (at a quick glance) looks big enough.
Another possible issue: if note is NULL or invalid then strlen(note) is not safe.

(Posted answer on behalf of the question author)
My problem was that I defined noteletter as string. I changed that part to
char noteletter[4];
int noteoctav;
if (strlen(note) == 3)
{
noteletter[0] = note[0];
noteletter[1] = note[1];
noteletter[2] = '\0';
noteoctav = note[2] - '0';
}
if (strlen(note)== 2)
{
noteletter[0] = note[0];
noteletter[1] = '\0';
noteoctav = note[1] - '0';
}
and now it works :)

Related

Issues using realloc (old size)

I'm trying to use realloc function in C, to dynamically operate on a char array of strings (char**).
I usually get a realloc():invalid old size error after 41st cicle of the for loop and I really can't understand why.
So, thanks to everyone who will help me ^-^
[EDIT] I'm trying to make the post more clear and following your advices, as a "new active member" of this community, so thank you all!
typedef struct _WordsOfInterest { // this is in an header file containing just
char **saved; // the struct and libraries
int index;
} wordsOfInterest;
int main() {
char *token1, *token2, *save1 = NULL, file[LEN], *temp, *word, **tokenArr;
int n=0, ch,ch2, flag=0, size, init=0,position,currEdit,init2=0,tempEdit,size_arr=LEN,
oldIndex=0,totalIndex=0,*editArr,counterTok=0;
wordsOfInterest toPrint;
char **final;
toPrint.index = 0;
toPrint.saved = malloc(sizeof(char*)*LEN);
editArr = malloc(sizeof(int)*LEN);
tokenArr = malloc(sizeof(char*)*LEN);
final = malloc(sizeof(char*)*1);
// external for loop
for(...) {
tokenArr[counterTok] = token1;
// internal while loop
while(...) {
// some code here surely not involved in the issue
} else {
if(init2 == 0) {
currEdit = config(token1,token2);
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
init2 = 1;
} else {
if((abs((int)strlen(token1)-(int)strlen(token2)))<=currEdit) {
if((tempEdit = config(token1,token2)) == currEdit) {
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
if(toPrint.index == size_arr-1) {
size_arr = size_arr*2;
toPrint.saved = realloc(toPrint.saved, size_arr);
}
} else if((tempEdit = config(token1,token2))<currEdit) {
freeArr(toPrint, size_arr);
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
currEdit = tempEdit;
}
}
}
flag = 0;
word = NULL;
temp = NULL;
freeArr(toPrint, size_arr);
}
}
editArr[counterTok] = currEdit;
init2 = 0;
totalIndex = totalIndex + toPrint.index + 1;
final = realloc(final, (sizeof(char*)*totalIndex));
uniteArr(toPrint, final, oldIndex);
oldIndex = toPrint.index;
freeArr(toPrint,size_arr);
fseek(fp2,0,SEEK_SET);
counterTok++;
}
You start with final uninitialized.
char **final;
change it to:
char **final = NULL;
Even if you are starting with no allocation, it needs a valid value (e.g. NULL) because if you don't initialize a local variable to NULL, it gets garbage, and realloc() will think it is reallocating a valid chunk of memory and will fail into Undefined Behaviour. This is probably your problem, but as you have eliminated a lot of code in between the declaration and the first usage of realloc, whe cannot guess what is happening here.
Anyway, if you have indeed initialized it, I cannot say, as you have hidden part of the code, unlistening the recommendation of How to create a Minimal, Reproducible Example
.
There are several reasons (mostly explained there) to provide a full but m inimal, out of the box, failing code. This allows us to test that code without having to provide (and probably solving, all or part) the neccesary code to make it run. If you only post a concept, you cannot expect from us complete, full running, and tested code, degrading strongly the quality of SO answers.
This means you have work to do before posting, not just eliminating what you think is not worth mentioning.
You need to build a sample that, with minimum code, shows the actual behaviour you see (a nonworking complete program) This means eliminating everything that is not related to the problem.
You need (and this is by far more important) to, before sending the code, to test it at your site, and see that it behaves as you see at home. There are many examples that, when eliminated the unrelated code, don't show the commented behaviour.
...and then, without touching anymore the code, send it as is. Many times we see code that has been touched before sending, and the problem dissapeared.
If we need to build a program, we will probably do it with many other mistakes, but not yours, and this desvirtuates the purpose of this forum.
Finally, sorry for the flame.... but it is necessary to make people read the rules.

Using a c-program to read an NMEA-string

I am trying to make a c-program that will will a string, but I want it only to read a very small part of it.
The NMEA-telegram that I try to read is $WIXDR, and do receive the necessary strings.
Here's 2 examples of strings that I get into the CPU:
$WIXDR,C,1.9,C,0,H,83.2,P,0,P,1023.9,H,0*46
$WIXDR,V,0.01,M,0,Z,10,s,0,R,0.8,M,0,V,0.0,M,1,Z,0,s,1,R,0.0,M,1,R,89.9,M,2,R,0.0,M,3*60
If it were only 1 string (not both C and V), this would not be a problem for me.
The problem here is that it's 2 seperate strings. One with the temperature, and one with rain-info.
The only thing that I'm interested in is the value "1.9" from
$WIXDR,C,1.9,C,0......
Here's what I have so far:
void ProcessXDR(char* buffPtr)
{
char valueBuff[10];
int result, x;
float OutSideTemp;
USHORT uOutSideTemp;
// char charTemperature, charRain
IODBerr eCode;
//Outside Temperature
result = ReadAsciiVariable(buffPtr, &valueBuff[0], &buffPtr, sizeof(valueBuff));
sscanf(&valueBuff[0],"%f",&OutSideTemp);
OutSideTemp *= 10;
uOutSideTemp = (USHORT)OutSideTemp;
eCode = IODBWrite(ANALOG_IN,REG_COM_XDR,1,&uOutSideTemp,NULL);
}
// XDR ...
if(!strcmp(&nmeaHeader[0],"$WIXDR"))
{
if(PrintoutEnable)printf("XDR\n");
ProcessXDR(buffPtr);
Timer[TIMER_XDR] = 1200; // Update every minute
ComStateXDR = 1;
eCode = IODBWrite(DISCRETE_IN,REG_COM_STATE_XDR,1,&ComStateXDR,NULL);
}
There's more, but this is the main part that I have.
I have found the answer to my own question. The code that would do as I intented is as follows:
What my little code does, is to look for the letter C, and if the C is found, it will take the value after it and put it into "OutSideTemp". The reason I had to look for C is that there is also a similar string received with the letter V (Rain).
If someone have any input in a way it could be better, I don't mind, but this little piece here does what I need it to do.
Here's to example telegrams I receive (I wanted the value 3.0 to be put into "OutSideTemp"):
$WIXDR,C,3.0,C,0,H,59.2,P,0,P,1026.9,H,04F
$WIXDR,V,0.00,M,0,Z,0,s,0,R,0.0,M,0,V,0.0,M,1,Z,0,s,1,R,0.0,M,1,R,89.9,M,2,R,0.0,M,358
void ProcessXDR(char* buffPtr)
{
char valueBuff[10];
int result, x;
float OutSideTemp;
USHORT uOutSideTemp;
// char charTemperature, charRain
IODBerr eCode;
// Look for "C"
result = ReadAsciiVariable(buffPtr, &valueBuff[0], &buffPtr, sizeof(valueBuff));
// sscanf(&valueBuff[0],"%f",&charTemperature);
if (valueBuff[0] == 'C')
//Outside Temperature
result = ReadAsciiVariable(buffPtr, &valueBuff[0], &buffPtr, sizeof(valueBuff));
sscanf(&valueBuff[0],"%f",&OutSideTemp);
OutSideTemp *= 10;
uOutSideTemp = (USHORT)OutSideTemp;
eCode = IODBWrite(ANALOG_IN,REG_COM_XDR,1,&uOutSideTemp,NULL);
}

Segmentation fault - weird debugging with gdb

I'm working in C, Linux terminal. I need to find a pattern in a text and recolor it. GDB debugging can locate the function that is causing the problem via (gdb) backtrace, but it shows me a terrible message when I try to find the exact line:
Error
Program received signal SIGSEGV, Segmentation fault.
strstr_sse2_unaligned ()
at ../sysdeps/x86_64/multiarch/strstr-sse2-unaligned.S:40
40 ../sysdeps/x86_64/multiarch/strstr-sse2-unaligned.S: No such file or dir
ectory.
(gbd)
The broken function is find_and_recolor:
char* my_replace(char *text, char* replacement)
{
int lgreplacement = strlen(replacement);
int lgtext = strlen(text);
char *aux = (char*)malloc((lgreplacement + lgtext + 10) * sizeof(char));
strcpy(aux, replacement);
strcat(aux, text);
return(aux);
}
char* find_and_recolor(char* text, char* pattern)
{
int lgpattern = strlen(pattern);
int lgreplace = lgpattern + 10;//there are exactly 10 characters that must be inserted along the pattern word
int dif = 0;
char *p;
char *replacement = (char*)malloc(lgreplace * sizeof(char));
strcpy(replacement, "\e[0;31m");
strcat(replacement, pattern);
strcat(replacement, "\e[m");//to recolor a word in red, that word must be surrounded by those characters
while(p = strstr(text + dif, pattern))
{
p = my_replace(p, replacement);
p += lgreplace;
dif = p - text;
}
free(replacement);
return strdup(text);
}
it shows me a terrible message when I try to find the exact line:
There is nothing terrible, weird or unusual about this message, you just need to learn proper debugging technique.
What's happening is that the segmentation fault doesn't happen in your code, it happens inside GLIBC code (inside strstr), because you called strstr with bad arguments.
To find which call to strstr that was, use GDB up command to step out of GLIBC code, and into your code. Once you are inside find_and_recolor, you would be able to see the exact line, and print values of text, dif and pattern which caused your crash (assuming you compiled your code for debugging, i.e. with the -g flag).
Updating diff to p-text in while loop where both pointer points to different array doesn't make sense. It is undefined behavior.
Also code has other issues.
Uninitialized variable.
Less optimized as number of call can be reduced.

Where does the error come from? Valgrind / C / insertString

for one of my project i have to make a new version of the function insertString,you could see the code below:
This function always gives me the desired result, (I made some Unit test), however the main issue is this one: even if it works in my IDE (compilation etc) it won't pass unit test using Valgrind, is there anyone who could see the error?
char * insertString(const char * src, int insertPosition, const char * toBeInserted,int insertLength)
{
size_t outputSize=stringLength(src)+(size_t)insertLength;
char* output=malloc(sizeof(char)*(outputSize+1));
int i;
if(output==NULL)
{
fatalError("error during memory allocation in InsertString");
}
for(i=0;i<insertPosition;i++)
{
output[i]=src[i];
}
for(i=0;i<insertLength;i++)
{
output[i+insertPosition]=toBeInserted[i];
}
for(i=0;i<=insertLength;i++)
{
output[i+insertPosition+insertLength]=src[insertPosition+i];
}
output[outputSize]='\0';
return output;
}
thank's for everything, and have a good Sunday!
The terminating condition, i<=insertLength, in your last loop:
for(i=0;i<=insertLength;i++)
{
output[i+insertPosition+insertLength]=src[insertPosition+i];
}
has nothing to do with the length remaining in src. If insertLength is large enough, the code will read past the end of src.
Change it to something like (I think):
for(i=0;i<=strlen(src)-insertPosition;i++)
{
output[i+insertPosition+insertLength]=src[insertPosition+i];
}
Also, in my opinion the code could be made much more easily understood (and therefore verifiable) by using a running index for the output buffer instead of resetting it to 0 for each loop and adding other values for the subscript. Alternatively, I think using pointers to traverse the various buffers would be more readable:
char* tmp = output;
for(i=0;i<insertPosition;i++)
{
*tmp++ = *src++;
}
for(i=0;i<insertLength;i++)
{
*tmp++ = *toBeInserted++;
}
for(i=insertPosition;i<=strlen(src);i++)
{
*tmp++ = *src++;
}
*tmp++ = '\0';

Advice on Segmentation Fault, using gdb effectively, C Programming (newbie)

I am having a problem with a segmentation fault working in C, and I cannot figure out why this is occurring. I think it has something to do with misuse of the fget(c) function.
while((ch = fgetc(fp))!= EOF) {
printf("Got inside first while: character is currently %c \n",ch); //**********DELETE
while(ch != '\n') {
char word[16]; //Clear out word before beginning
i = i+1; //Keeps track of the current run thru of the loop so we know what input we're looking at.
while(ch != ' ') {
printf("%c ",ch); //**********DELETE
//The following block builds up a character array from the current "word" (separated by spaces) in the input file.
int len = strlen(word);
word[len] = ch;
word[len+1] = '\0';
printf("%s",word);
ch = fgetc(fp);
}
//The following if-else block sets the variables TextA, TextB, and TextC to the appropriate Supply Types from the input.
//This part may be confusing to read mentally, but not to trace. All it does is logically set TextA, B, and C to the 3 different possible values SupplyType.
if(word!=TextB && word!=TextC && i==1 && TextB!="") {
strcpy(TextA,word);
}
else if(word!=TextA && word!=TextC && i==1 && TextC!="") {
strcpy(TextB,word);
}
else if(word!=TextB && word!=TextA && i==1) {
strcpy(TextC,word);
}
switch(i) {
case 1:
if(TextA == word) {
SubTypeOption = 1;
}
else if(TextB == word) {
SubTypeOption = 2;
}
else if(TextC == word) {
SubTypeOption = 3;
}
break;
case 2:
//We actually ultimately don't need to keep track of the product's name, so we do nothing for case i=2. Included for readibility.
break;
case 3:
WholesalePrice = atof(word);
break;
case 4:
WholesaleAmount = atoi(word);
break;
case 5:
RetailPrice = atof(word);
break;
case 6:
RetailAmount = atoi(word);
break;
}//End switch(i)
ch = fgetc(fp);
}//End while(ch != '\n')
//The following if-else block "tallys up" the total amounts of SubTypes bought and sold by the owner.
if(SubTypeOption == 1) {
SubType1OwnersCost = SubType1OwnersCost + (WholesalePrice*(float)WholesaleAmount);
SubType1ConsumersCost = SubType1ConsumersCost + (RetailPrice *(float)RetailAmount);
}
else if(SubTypeOption == 2) {
SubType2OwnersCost = SubType2OwnersCost + (WholesalePrice*(float)WholesaleAmount);
SubType2ConsumersCost = SubType2ConsumersCost + (RetailPrice *(float)RetailAmount);
}
else if(SubTypeOption == 3) {
SubType3OwnersCost = SubType3OwnersCost + (WholesalePrice*(float)WholesaleAmount);
SubType3ConsumersCost = SubType3ConsumersCost + (RetailPrice *(float)RetailAmount);
}
}//End while((ch = fgetc(fp))!= EOF)
Using gdb (just a simple run of the a.out) I found that the problem is related to getc, but it does not tell which line/which one. However, my program does output "Got in side the first while: character is currently S". This S is the first letter in my input file, so I know it is working somewhat how it should, but then causes a seg fault.
Does anyone have any advice on what could be going wrong, or how to debug this problem? I am relatively new to C and confused mostly on syntax. I have a feeling I've done some small syntactical thing wrong.
By the way, this snippet of the code is meant to get a word from a string. Example:
Help me with this program please
should give word equaling "Help"
Update: Now guys I am getting kind of a cool error (although cryptic). When I recompiled I got something like this:
word is now w S
word is now w Su
word is now w Sup
... etc except it goes on for a while, building a pyramid of word.
with my input file having only the string "SupplyTypeA 1.23 1 1.65 1" in it.
UPDATE: Segmentation fault was fixed (the issue was, I was going past the end of the file using fgetc() ). Thanks everyone.
If anyone still glances at this, could they help me figure out why my output file does not contain any of the correct numbers it should? I think I am probably misusing atof and atoi on the words I'm getting.
Make sure you compile the program with -g -O0 options
Next step through the program line by line in GDB, watch and understand what your program is doing. Look at the various variables. This is the essential debugging skill.
WHen it dies type the command 'k' this will give you a stack trace the last line of the trace will have the failing line number, but you know that anyway because you were on the line shen you did a step command
There is no "fget" in good old C, but maybe you're using a more modern version that has something named "fget". Most likely, you meant to use "fgetc". When a C I/O function starts with "f", it usually wants a FILE* handle as an argument, as "fgetc" does. Try using "fgetc" instead, after reading the documentation for it.

Resources