在 C 中退出分段错误结构
Exited segmentation fault Struct in C
所以我有一个结构,我想创建一个带有循环的函数,该循环从用户输入中获取并将它们存储到结构中。但是在 1 个循环之后程序因分段错误而崩溃,我找不到问题所在。
错误如下:
> clang-7 -pthread -lm -o main main.c
> ./main
4
ath
67
68
thes
exited, segmentation fault
>
代码如下:
#define STR 100000
typedef struct city{
float x;
float y;
char *name;
}City;
City *GetCities(int *N){
int i;
City *p;
char c;
scanf("%d",&*N);
p=malloc(sizeof(City));
p->name=malloc(STR*sizeof(char));
if (p->name==NULL){
printf("Could not find enough memory");
}
for (i=0; i<*N; i++){
while((c = getchar()) !='\n' && c!= EOF);
fgets(p[i].name,STR,stdin);
p[strcspn(p[i].name,"\n")].name="[=11=]";
p[i].name=realloc(p[i].name,(strlen(p[i].name)+1)*sizeof(char));
scanf("%f ",&p[i].x);
scanf("%f",&p[i].y);
}
return p;
}
这个会起作用:
//includes were missing
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STR 100000
typedef struct city{
float x;
float y;
char *name;
}City;
City *GetCities(int *N){
int i;
char c;
City *list, *city;
//N is already a pointer so using a '&*' is confusing and I'm unsure whether this is at all valid syntax
scanf("%d", N);
//allocate enough memory! multiplied by number of cities
list = malloc(sizeof(City) * (*N));
for (i=0; i < *N; i++) {
//use pointer arithmetic to get the current city from the allocated block
//this needs to be done only once, now you can go on and reuse it extensively
city = list + i;
city->name = malloc(STR * sizeof(char));
if (city->name==NULL){
printf("Could not find enough memory");
}
while((c = getchar()) !='\n' && c!= EOF);
//i hope rest is clear
fgets(city->name, STR, stdin);
//use city->name[strlen(city->name)-1]='[=10=]' instead?
city->name[strcspn(city->name,"\n")]='[=10=]';
//at least you didn't forget the +1 in the realloc! :-)
city->name = realloc(city->name,(strlen(city->name)+1)*sizeof(char));
scanf("%f ", &city->x);
scanf("%f", &city->y);
}
return list;
}
//please also show the main, but I guess it was something like this
int main () {
int i, n;
City *cities, *city;
cities = GetCities(&n);
for (i=0; i < n; i++) {
city = cities + i;
printf("The %dth city \"%s\" got coordinates x=%f and y=%f!\n", i, city->name, city->x, city->y);
//don't forget to free the name
free(city->name);
}
//don't forget to free the memory
free(cities);
}
我还建议在循环中使用较小的行长度缓冲区和 运行 fgets 以节省 ram space。
要求输入包括即将到来的数据的总数通常是一个糟糕的设计选择,并且很容易删除该要求。例如:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
FILE * xfopen(const char *, const char *);
void * xrealloc(void *, size_t, size_t, void *);
struct city{
float x, y;
char *name;
};
int
get_city(struct city *e)
{
int c;
char *end;
size_t cap = 32;
e->name = xrealloc(NULL, 1, cap, &end);
/* Copy one line. We coould use getline(), or "%m[^\n]" */
while( (c = getchar()) != EOF && c != '\n' ){
*end++ = c;
if( end == e->name + cap ){
e->name = xrealloc(e->name, 1, cap += 32, &end);
}
}
*end = '[=10=]';
if( c == EOF ){
return EOF;
}
if( (c = scanf("%f %f ", &e->x, &e->y)) != 2 ){
if( c != EOF ){
fprintf(stderr, "Invalid input\n");
}
return EOF;
}
return 0;
}
struct city *
GetCities(int *n)
{
size_t cap = 4;
struct city *e, *p = xrealloc(NULL, sizeof *p, cap, &e);
while( get_city(e) != EOF ){
if( ++e == p + cap ){
p = xrealloc(p, sizeof *p, cap += 4, &e);
}
}
*n = e - p;
return p;
}
int
main(void)
{
int n;
while( (n = getchar()) != EOF && n != '\n' ){
; /* Discard first line of input */
}
struct city *p = GetCities(&n);
struct city *e = p + n;
for( ; p < e; p++ ){
printf("%s: %f, %f\n", p->name, p->x, p->y);
}
return 0;
}
void *
xrealloc(void *buf, size_t num, size_t siz, void *endvp)
{
char **endp = endvp;
char *b = buf;
ptrdiff_t offset = b && endp && *endp ? *endp - b : 0;
b = realloc(b, num * siz);
if( b == NULL ){
perror("realloc");
exit(EXIT_FAILURE);
}
if( endp != NULL ){
*endp = b + offset;
}
return b;
}
要使程序运行,您需要做三件基本的事情:
- 分配N个城市
- 对于每个城市,在读取名称之前为名称分配内存
- 正确终止名称(分配空字符,而不是字符串)
这是更正后的代码:
City *GetCities(int *N)
{
int i;
City *p;
char c;
scanf("%d", N);
p = malloc(*N * sizeof(City));
for (i = 0; i < *N; i++) {
p[i].name = malloc(STR * sizeof(char));
if (p[i].name == NULL) {
printf("Could not find enough memory");
}
while ((c = getchar()) != '\n' && c != EOF);
fgets(p[i].name, STR, stdin);
p[i].name[strcspn(p[i].name, "\n")] = '[=10=]';
scanf("%f ", &p[i].x);
scanf("%f", &p[i].y);
}
return p;
}
剩下的就是验证输入并确保第一次调用 malloc 不会失败。您可能还需要一个函数来释放分配的内存。
所以我有一个结构,我想创建一个带有循环的函数,该循环从用户输入中获取并将它们存储到结构中。但是在 1 个循环之后程序因分段错误而崩溃,我找不到问题所在。
错误如下:
> clang-7 -pthread -lm -o main main.c
> ./main
4
ath
67
68
thes
exited, segmentation fault
>
代码如下:
#define STR 100000
typedef struct city{
float x;
float y;
char *name;
}City;
City *GetCities(int *N){
int i;
City *p;
char c;
scanf("%d",&*N);
p=malloc(sizeof(City));
p->name=malloc(STR*sizeof(char));
if (p->name==NULL){
printf("Could not find enough memory");
}
for (i=0; i<*N; i++){
while((c = getchar()) !='\n' && c!= EOF);
fgets(p[i].name,STR,stdin);
p[strcspn(p[i].name,"\n")].name="[=11=]";
p[i].name=realloc(p[i].name,(strlen(p[i].name)+1)*sizeof(char));
scanf("%f ",&p[i].x);
scanf("%f",&p[i].y);
}
return p;
}
这个会起作用:
//includes were missing
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STR 100000
typedef struct city{
float x;
float y;
char *name;
}City;
City *GetCities(int *N){
int i;
char c;
City *list, *city;
//N is already a pointer so using a '&*' is confusing and I'm unsure whether this is at all valid syntax
scanf("%d", N);
//allocate enough memory! multiplied by number of cities
list = malloc(sizeof(City) * (*N));
for (i=0; i < *N; i++) {
//use pointer arithmetic to get the current city from the allocated block
//this needs to be done only once, now you can go on and reuse it extensively
city = list + i;
city->name = malloc(STR * sizeof(char));
if (city->name==NULL){
printf("Could not find enough memory");
}
while((c = getchar()) !='\n' && c!= EOF);
//i hope rest is clear
fgets(city->name, STR, stdin);
//use city->name[strlen(city->name)-1]='[=10=]' instead?
city->name[strcspn(city->name,"\n")]='[=10=]';
//at least you didn't forget the +1 in the realloc! :-)
city->name = realloc(city->name,(strlen(city->name)+1)*sizeof(char));
scanf("%f ", &city->x);
scanf("%f", &city->y);
}
return list;
}
//please also show the main, but I guess it was something like this
int main () {
int i, n;
City *cities, *city;
cities = GetCities(&n);
for (i=0; i < n; i++) {
city = cities + i;
printf("The %dth city \"%s\" got coordinates x=%f and y=%f!\n", i, city->name, city->x, city->y);
//don't forget to free the name
free(city->name);
}
//don't forget to free the memory
free(cities);
}
我还建议在循环中使用较小的行长度缓冲区和 运行 fgets 以节省 ram space。
要求输入包括即将到来的数据的总数通常是一个糟糕的设计选择,并且很容易删除该要求。例如:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
FILE * xfopen(const char *, const char *);
void * xrealloc(void *, size_t, size_t, void *);
struct city{
float x, y;
char *name;
};
int
get_city(struct city *e)
{
int c;
char *end;
size_t cap = 32;
e->name = xrealloc(NULL, 1, cap, &end);
/* Copy one line. We coould use getline(), or "%m[^\n]" */
while( (c = getchar()) != EOF && c != '\n' ){
*end++ = c;
if( end == e->name + cap ){
e->name = xrealloc(e->name, 1, cap += 32, &end);
}
}
*end = '[=10=]';
if( c == EOF ){
return EOF;
}
if( (c = scanf("%f %f ", &e->x, &e->y)) != 2 ){
if( c != EOF ){
fprintf(stderr, "Invalid input\n");
}
return EOF;
}
return 0;
}
struct city *
GetCities(int *n)
{
size_t cap = 4;
struct city *e, *p = xrealloc(NULL, sizeof *p, cap, &e);
while( get_city(e) != EOF ){
if( ++e == p + cap ){
p = xrealloc(p, sizeof *p, cap += 4, &e);
}
}
*n = e - p;
return p;
}
int
main(void)
{
int n;
while( (n = getchar()) != EOF && n != '\n' ){
; /* Discard first line of input */
}
struct city *p = GetCities(&n);
struct city *e = p + n;
for( ; p < e; p++ ){
printf("%s: %f, %f\n", p->name, p->x, p->y);
}
return 0;
}
void *
xrealloc(void *buf, size_t num, size_t siz, void *endvp)
{
char **endp = endvp;
char *b = buf;
ptrdiff_t offset = b && endp && *endp ? *endp - b : 0;
b = realloc(b, num * siz);
if( b == NULL ){
perror("realloc");
exit(EXIT_FAILURE);
}
if( endp != NULL ){
*endp = b + offset;
}
return b;
}
要使程序运行,您需要做三件基本的事情:
- 分配N个城市
- 对于每个城市,在读取名称之前为名称分配内存
- 正确终止名称(分配空字符,而不是字符串)
这是更正后的代码:
City *GetCities(int *N)
{
int i;
City *p;
char c;
scanf("%d", N);
p = malloc(*N * sizeof(City));
for (i = 0; i < *N; i++) {
p[i].name = malloc(STR * sizeof(char));
if (p[i].name == NULL) {
printf("Could not find enough memory");
}
while ((c = getchar()) != '\n' && c != EOF);
fgets(p[i].name, STR, stdin);
p[i].name[strcspn(p[i].name, "\n")] = '[=10=]';
scanf("%f ", &p[i].x);
scanf("%f", &p[i].y);
}
return p;
}
剩下的就是验证输入并确保第一次调用 malloc 不会失败。您可能还需要一个函数来释放分配的内存。