英文:
Weird characters in output
问题
I have extracted and translated the code portions for you. Here's the translated code:
typedef struct {
char *title;
char isbn[MAX_ISBN];
char *authors;
char *publisher;
} Book;
typedef struct {
Book **refs;
int size;
int space;
} VecBookRef;
typedef struct {
VecBookRef *titleVec;
VecBookRef *isbnVec;
} DynCollection;
#include <stdio.h>
#include <stdlib.h>
#include "vector.h"
#include "book.h"
#include "collection.h"
#include "splitfield.h"
int main() {
char input[100];
DynCollection *col;
FILE *f = fopen("dados.csv", "r");
if (f == NULL) {
printf("Error opening file");
return 0;
}
vecRefCreate();
col = collecBuild(f);
if (col == NULL) {
printf("Error creating collection");
return 0;
}
fclose(f);
do {
printf("\nEnter a command (t, i + isbn, q): ");
fgets(input, sizeof(input), stdin);
int inputLen = strlen(input);
if (inputLen == 2 && input[0] == 't') {
vecRefScan(col->titleVec, NULL, printBook);
} else if (inputLen > 2 && input[0] == 'i' && input[1] == ' ') {
char isbn[MAX_ISBN];
sscanf(input + 2, "%s", isbn);
if (strlen(isbn) != 13) {
printf("\nInvalid ISBN\n");
continue;
}
Book *b = vecRefSearchIsbn(col->isbnVec, isbn);
if (b != NULL) {
printBook(b, NULL);
} else {
printf("\nNo book was found with the entered ISBN\n");
continue;
}
}
if (inputLen == 2 && input[0] == 'q') {
collecFree(col);
printf("Memory freed");
}
} while (input[0] != 'q');
return 0;
}
Book *vecRefSearchIsbn(VecBookRef *vec, char *isbn) {
int comparator(const void *key, const void *book) {
const char *isbn = (const char *)key;
const Book *b = *(const Book **)book;
return strcmp(isbn, b->isbn);
}
Book *b = (Book *)bsearch(isbn, vec->refs, vec->size, sizeof(Book *), comparator);
if (b != NULL) {
return b;
} else return NULL;
}
void printBook(Book *b, void *context) {
printf("\nTitle: %s\nISBN: %s\nAuthors: %s\nPublisher: %s\n", b->title, b->isbn, b->authors, b->publisher);
}
Please let me know if you need any further assistance with this code.
英文:
I have this program that extracts book data(title, isbn, authors and publisher) from a file and then populates 3 structs. The structs are all correctly populated and the command "t" that prints all the books alphabetically in order is working correctly. So everything up until that point works but then if I try to use the "i 'isbn'" (ex.: i 9780321942050) command it doesn't work. It prints some weird characters and I've tried everything in the range of function of my brain to try and fix it but nothing worked. From what I could understand the problem is in the vecRefSearchIsbn function and what it returns because everything is being passed correctly up until that point. I don't have that much knowledge about pointers so I may be missing something but I've tried a lot of things so I'm not going to list them all. I provided the main function and the vecRefSearchIsbn function because that is where I think the problem resides but if someones thinks that the problem is elsewhere I won't hesitate to provide any other functions.
This is what I get in the output:
Digite um comando (t, i + isbn, q): i 9780321942050
Title:p▬┼%7☻
ISBN: 0z┼%7☻
Authors: ░É┼%7☻
Publisher: `¡┼%7☻
typedef struct {
char *title;
char isbn[MAX_ISBN];
char *authors;
char *publisher;
} Book;
typedef struct{
Book **refs;
int size;
int space;
} VecBookRef;
typedef struct{
VecBookRef *titleVec;
VecBookRef *isbnVec;
} DynCollection;
#include <stdio.h>
#include <stdlib.h>
#include "vector.h"
#include "book.h"
#include "collection.h"
#include "splitfield.h"
int main(){
char input[100];
DynCollection *col;
FILE *f=fopen("dados.csv", "r");
if(f==NULL){
printf("Erro ao abrir ficheiro");
return 0;
}
vecRefCreate();
col=collecBuild(f);
if(col==NULL){
printf("Erro ao criar coleção");
return 0;
}
fclose(f);
do{
printf("\nDigite um comando (t, i + isbn, q): ");
fgets(input, sizeof(input), stdin);
int inputLen=strlen(input);
if(inputLen==2 && input[0]=='t'){
vecRefScan(col->titleVec, NULL, printBook);
}
else if(inputLen>2 && input[0]=='i' && input[1]==' '){
char isbn[MAX_ISBN];
sscanf(input+2, "%s", isbn);
if(strlen(isbn)!=13){
printf("\nISBN invalido\n");
continue;
}
Book *b=vecRefSearchIsbn(col->isbnVec, isbn);
if(b!=NULL){
printBook(b, NULL);
}else{
printf("\nNao foi encontrado um livro com o ISBN inserido\n");
continue;
}
}
if(inputLen==2 && input[0]=='q'){
collecFree(col);
printf("Memoria limpa");
}
}while(input[0]!='q');
return 0;
}
Book *vecRefSearchIsbn(VecBookRef *vec, char *isbn){
int comparator(const void *key, const void *book){
const char *isbn=(const char *)key;
const Book *b=*(const Book **)book;
return strcmp(isbn, b->isbn);
}
Book *b=(Book*)bsearch(isbn, vec->refs, vec->size, sizeof(Book *), comparator);
if(b!=NULL){
return b;
}else return NULL;
}
void printBook(Book *b, void *context){
printf("\nTitle:%s\nISBN: %s\nAuthors: %s\nPublisher: %s\n", b->title, b->isbn, b->authors, b->publisher);
}
答案1
得分: 0
始终在使用 `*scanf()` 读取字符串时使用最大字段宽度,否则用户输入过多数据会导致缓冲区溢出。如果事后再检查,已经为时太晚:
```c
char isbn[MAX_ISBN];
sscanf(input+2, "%s", isbn);
if(strlen(isbn)!=13){
否则,数据破坏/错误可能出现在您未显示的代码中。我做了以下更改:
- 将
MAX_ISBN
从14
更改为13
(必需与str()
宏一致)。 - 将
isbn
定义更改为使用MAX_ISBN+1
。 - 定义
INPUT_LEN
替代内联的魔术数字 100。 - (未修复)检查
fgets()
是否返回 NULL。 - 从
input
中删除尾随的换行符,因为您可能不关心它。如果关心,请检查overflow
是否为\n
。 - 不要调用
strlen()
,而是使用可以处理可能太小的输入的函数,即strcmp()
、strncmp()
。话虽如此,我可能会考虑在input[0]
上开关,即使这意味着现在您需要使用 goto 退出循环,而不是使用 break。 - 为过大的
isbn
更改错误处理,并使用最大字段宽度读取它。 - 使用 break/goto 而不是两次测试退出条件。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_ISBN 13
#define INPUT_LEN 100
#define str(s) str2(s)
#define str2(s) #s
typedef struct {
char *title;
char isbn[MAX_ISBN+1];
char *authors;
char *publisher;
} Book;
int main(void) {
char input[INPUT_LEN];
for(;;) {
printf("\nDigite um comando (t, i + isbn, q): ");
fgets(input, sizeof(input), stdin);
input[strcspn(input, "\n")] = '\0';
if(!strncmp(input, "i ", 2)) {
char isbn[MAX_ISBN+1];
char overflow;
if(sscanf(input+2, "%" str(MAX_ISBN) "s%c", isbn, &overflow) != 1) {
printf("\nISBN invalido\n");
continue;
}
printf("%s\n", isbn);
} else if(!strcmp(input, "q")) {
printf("Memoria limpa");
break;
}
}
}
示例会话:
Digite um comando (t, i + isbn, q): i 9780321942050
9780321942050
Digite um comando (t, i + isbn, q): i 9780321942050x
ISBN invalido
Digite um命令(t,i + isbn,q):q
英文:
Always use a maximum field width when reading a string with *scanf()
as this will cause a buffer overflow if user enters too much data. It's too late to check after the fact:
char isbn[MAX_ISBN];
sscanf(input+2, "%s", isbn);
if(strlen(isbn)!=13){
Otherwise the corruption/error is in code you haven't shown us. I made the following changes:
- Changed
MAX_ISBN
from14
to13
(required for the str() macro). - Changed
isbn
definition to useMAX_ISBN+1
. - Define
INPUT_LEN
instead of the magic number 100 inline. - (Not fixed) Check if
fgets()
returns NULL. - Strip the trailing newline from
input
as you probably don't care about it. If you do then you check thatoverflow
is\n
. - Don't call
strlen()
just use functions that can deal with input that is possible too small, i.e.strcmp()
,strncmp()
. That said, I might be tempted to switch oninput[0]
even if means you now need to use a goto to exit the loop instead of the break. - Changed error handling for too large a
isbn
, and used a maximum field width to read it. - Use break/goto instead of testing the exit condition twice.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_ISBN 13
#define INPUT_LEN 100
#define str(s) str2(s)
#define str2(s) #s
typedef struct {
char *title;
char isbn[MAX_ISBN+1];
char *authors;
char *publisher;
} Book;
int main(void) {
char input[INPUT_LEN];
for(;;) {
printf("\nDigite um comando (t, i + isbn, q): ");
fgets(input, sizeof(input), stdin);
input[strcspn(input, "\n")] = '\0';
if(!strncmp(input, "i ", 2)) {
char isbn[MAX_ISBN+1];
char overflow;
if(sscanf(input+2, "%" str(MAX_ISBN) "s%c", isbn, &overflow) != 1) {
printf("\nISBN invalido\n");
continue;
}
printf("%s\n", isbn);
} else if(!strcmp(input, "q")) {
printf("Memoria limpa");
break;
}
}
}
and example session:
Digite um comando (t, i + isbn, q): i 9780321942050
9780321942050
Digite um comando (t, i + isbn, q): i 9780321942050x
ISBN invalido
Digite um comando (t, i + isbn, q): q
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论