C电话簿程序:将光标重新定位在文本文件中以开始上一行

时间:2013-03-31 00:41:47

标签: c cursor text-files fseek fputs

编写一个C程序,打开一个名为phoneList.txt的文本文件并搜索联系人(名字,姓氏,电话号码),并更新现有联系人的电话号码。我的问题出在更新电话号码程序中。当我使用fgets查找匹配的名称来更新联系人时,光标位于下一行的开头,也就是在与用户搜索匹配的联系人之后的联系开始时。 继承我的代码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(void){
struct record{
        char firstName[20];
        char lastName[20];
        char phoneNum[15];
    };
    struct record info;
    FILE *fp;
    char line[100];
    char phoneInfo[100];
    char fullName[100];
    char *stream;
    int n = atoi(getenv("CONTENT_LENGTH"));
    fgets(stream, n+1, stdin);  //put query string into stream from stdin
        //SET HTML OUTPUT AND TITLE, TEST CONTENT OF STREAM
    printf("%s%c%c\n", "Content-type:text/html;charset=iso-8859-1",13,10);
    printf("<p>%s</p>", stream);
    sscanf(stream, "firstName=%[^&]&lastName=%[^&]&phoneNum=%s", info.firstName, info.lastName, info.phoneNum);
    strcpy(fullName, info.firstName);
    strcat(fullName, " ");
    strcat(fullName, info.lastName);
    strcpy(phoneInfo, fullName);
    strcat(phoneInfo, " ");
    strcat(phoneInfo, info.phoneNum);
    //strcat(phoneInfo, "\n");
    printf("%s", phoneInfo);
    printf("\n");
        //TEST FORMATTING OF PHONE INFO VAR
    fp = fopen("phoneList.txt", "r+");
    if(fp == NULL){
        printf("Error opening the file.\n");
        return 1;
    }
    while(fgets(line, 99, fp)!=NULL){
        if(strstr(line, fullName)!= NULL){
            //fseek(fp, -(strlen(phoneInfo)+1), SEEK_CUR);
            fputs(phoneInfo, fp);
            printf("Success! Number updated. \n");
            fclose(fp);
            return;
        }
    }
    if(feof(fp)){
        //fputs(phoneInfo, fp);
        printf("goes to here");
    }
    fclose(fp);
    return 0;
}

我有fseek评论,因为它的行为很奇怪,具体取决于被搜索的联系人是否在列表的末尾。我认为这与文本文件中有一个\ n字符有关。想知道是否有更好的方法来简单地覆盖与用户搜索匹配的行,或者至少将光标重置为与搜索匹配的行的开头。我已经做了一堆谷歌搜索和搜索这个网站,但我无法找到我理解如何实现的任何东西。真的很感谢你的帮助! 干杯

2 个答案:

答案 0 :(得分:1)

  

我有fseek评论,因为它的行为很奇怪,具体取决于被搜索的联系人是否在列表的末尾。

fseek(fp, -(strlen(phoneInfo)+1), SEEK_CUR);

在最后一行,您应该返回strlen(phoneInfo),而不是strlen(phoneInfo)+1。

因为在其他行中,有一个换行符。但在最后一行,可能没有。您可以采用效率较低的方式对其进行修改:

if(line[strlen(line)-1]=="\n"){
    fseek(fp, -(strlen(phoneInfo)+1), SEEK_CUR);
}
else{
    fseek(fp, -strlen(phoneInfo), SEEK_CUR);
}

顺便说一句,如果phoneInfo的长度与txt文件中的相同,则代码只能正常工作。

答案 1 :(得分:0)

您必须在给定文件流的读取和写入之间执行定位操作。

ISO / IEC 9899:2011第7.21.5.3节fopen函数

  

¶7以更新模式打开文件时('+'作为第二个或第三个字符)   在上面的模式参数值列表中,输入和输出都可以在上面执行   相关流。但是,如果没有输入,输出不应直接输入   干预调用fflush函数或文件定位函数(fseek,   fsetposrewind),输入不得直接跟随没有输出的输出   干预调用文件定位功能,除非输入操作遇到结束   文件。

您的代码必须执行某种fseek()来重新定位文件以进行写入;在继续阅读更多之后,它还必须在写完之后再做fseek()。您可能需要在阅读之前跟踪读取行的位置(ftell()fseek()fsetpos()),以便您可以再次找到该行的开头。

另外,鉴于:

char line[100];

致电fgets()

while (fgets(line, 99, fp)!=NULL){

是安全的,但你可以同样安全地使用:

while (fgets(line, sizeof(line), fp) != NULL)

并使用您分配的所有空间,而不是仅仅99%。此外,如果将行长度从100更改为256或1024或4096,则只需更改声明 - 而不是更改使用的位置。

以类似的方式,你有:

struct record
{
    char firstName[20];
    char lastName[20];
    char phoneNum[15];
};
struct record info;
FILE *fp;
char line[100];
char phoneInfo[100];
char fullName[100];
char *stream;

int n = atoi(getenv("CONTENT_LENGTH"));
fgets(stream, n+1, stdin);  //put query string into stream from stdin

您没有为stream分配空间来指向;你在你的课程中写作和随机的位置。

    //SET HTML OUTPUT AND TITLE, TEST CONTENT OF STREAM
printf("%s%c%c\n", "Content-type:text/html;charset=iso-8859-1",13,10);
printf("<p>%s</p>", stream);

sscanf(stream, "firstName=%[^&]&lastName=%[^&]&phoneNum=%s",
       info.firstName, info.lastName, info.phoneNum);

sscanf()应以各种方式升级:

if (sscanf(stream, "firstName=%19[^&]&lastName=%19[^&]&phoneNum=%14s",
           info.firstName, info.lastName, info.phoneNum) != 3)
{
    ...sscanf failed...
}

这会对结构的字段强制执行正确的长度(请注意,您的变量使用20和15,但格式必须使用19和14 - 这个逐个也是溢出源),并检查转换都是成​​功的。

顺便说一句,如果新字符串和旧字符串的长度相同,那么在旧字母上写新电话号码是安全的。如果新字符串较短,则需要将其填充到旧的长度以删除旧数字的最后几位数字。如果新字符串更长,你就会遇到重大问题;你将覆盖下一个条目的开头。您必须按适当的字节数(旧条目和新条目之间的长度差异)随机播放文件的内容。有关可以将数据插入文件中间的代码,请参阅SO 10467711

另请注意,文本文件的正式限制比二进制文件更多。然而,其中许多更理论而不是实际,特别是在Unix上。 I / O系统对文本文件执行CRLF到NL映射(这是Windows上的一个问题),这是约束的一个原因。